diff --git a/lib/config/migration.ts b/lib/config/migration.ts
index 7d1f4b16718893a43fd225fbb4e20ba8572db7b9..3679b9b01e3fd66fcf869d8255d49ee9a81f4de6 100644
--- a/lib/config/migration.ts
+++ b/lib/config/migration.ts
@@ -31,26 +31,9 @@ export function migrateConfig(config: RenovateConfig): MigratedConfig {
     }
     const newConfig = MigrationsService.run(config);
     const migratedConfig = clone(newConfig) as MigratedRenovateConfig;
-    const depTypes = [
-      'dependencies',
-      'devDependencies',
-      'engines',
-      'optionalDependencies',
-      'peerDependencies',
-    ];
+
     for (const [key, val] of Object.entries(newConfig)) {
-      if (depTypes.includes(key)) {
-        migratedConfig.packageRules = is.array(migratedConfig.packageRules)
-          ? migratedConfig.packageRules
-          : [];
-        const depTypePackageRule = migrateConfig(
-          val as RenovateConfig
-        ).migratedConfig;
-        depTypePackageRule.depTypeList = [key];
-        delete depTypePackageRule.packageRules;
-        migratedConfig.packageRules.push(depTypePackageRule);
-        delete migratedConfig[key];
-      } else if (is.string(val) && val.includes('{{baseDir}}')) {
+      if (is.string(val) && val.includes('{{baseDir}}')) {
         migratedConfig[key] = val.replace(
           regEx(/{{baseDir}}/g),
           '{{packageFileDir}}'
@@ -70,26 +53,6 @@ export function migrateConfig(config: RenovateConfig): MigratedConfig {
           '{{semanticPrefix}}',
           '{{#if semanticCommitType}}{{semanticCommitType}}{{#if semanticCommitScope}}({{semanticCommitScope}}){{/if}}: {{/if}}'
         );
-      } else if (key === 'depTypes' && is.array(val)) {
-        val.forEach((depType) => {
-          if (is.object(depType) && !is.array(depType)) {
-            const depTypeName = (depType as any).depType;
-            if (depTypeName) {
-              migratedConfig.packageRules = is.array(
-                migratedConfig.packageRules
-              )
-                ? migratedConfig.packageRules
-                : [];
-              const newPackageRule = migrateConfig(
-                depType as RenovateConfig
-              ).migratedConfig;
-              delete newPackageRule.depType;
-              newPackageRule.depTypeList = [depTypeName];
-              migratedConfig.packageRules.push(newPackageRule);
-            }
-          }
-        });
-        delete migratedConfig.depTypes;
       } else if (optionTypes[key] === 'object' && is.boolean(val)) {
         migratedConfig[key] = { enabled: val };
       } else if (optionTypes[key] === 'boolean') {
diff --git a/lib/config/migrations/custom/dep-types-migration.spec.ts b/lib/config/migrations/custom/dep-types-migration.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..4c21e9d053f0154b62f92aeb001207cc39197ad4
--- /dev/null
+++ b/lib/config/migrations/custom/dep-types-migration.spec.ts
@@ -0,0 +1,90 @@
+import { DepTypesMigration } from './dep-types-migration';
+
+describe('config/migrations/custom/dep-types-migration', () => {
+  it('should only add depTypes to packageRules', () => {
+    expect(DepTypesMigration).toMigrate(
+      {
+        peerDependencies: {
+          versionStrategy: 'widen',
+        },
+        dependencies: {
+          versionStrategy: 'widen',
+        },
+        engines: {
+          rangeStrategy: 'auto',
+        },
+        optionalDependencies: {
+          versionStrategy: 'widen',
+        },
+        devDependencies: {
+          versionStrategy: 'widen',
+        },
+        depTypes: [
+          'dependencies',
+          {
+            depType: 'optionalDependencies',
+            respectLatest: false,
+          },
+        ],
+        packageRules: [
+          {
+            packagePatterns: '^(@angular|typescript)' as never,
+            groupName: ['angular packages'] as never,
+            excludedPackageNames: 'foo',
+          },
+          {
+            packageNames: ['foo'],
+            packageRules: [
+              {
+                depTypeList: ['bar'],
+                automerge: true,
+              },
+            ],
+          },
+        ],
+      },
+      {
+        packageRules: [
+          {
+            packagePatterns: '^(@angular|typescript)' as never,
+            groupName: ['angular packages'] as never,
+            excludedPackageNames: 'foo',
+          },
+          {
+            packageNames: ['foo'],
+            packageRules: [
+              {
+                depTypeList: ['bar'],
+                automerge: true,
+              },
+            ],
+          },
+          {
+            matchDepTypes: ['peerDependencies'],
+            versionStrategy: 'widen',
+          },
+          {
+            matchDepTypes: ['dependencies'],
+            versionStrategy: 'widen',
+          },
+          {
+            matchDepTypes: ['engines'],
+            rangeStrategy: 'auto',
+          },
+          {
+            matchDepTypes: ['optionalDependencies'],
+            versionStrategy: 'widen',
+          },
+          {
+            matchDepTypes: ['devDependencies'],
+            versionStrategy: 'widen',
+          },
+          {
+            matchDepTypes: ['optionalDependencies'],
+            respectLatest: false,
+          },
+        ],
+      }
+    );
+  });
+});
diff --git a/lib/config/migrations/custom/dep-types-migration.ts b/lib/config/migrations/custom/dep-types-migration.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f7a824729b69c3263ad0b819cae446f3cb229605
--- /dev/null
+++ b/lib/config/migrations/custom/dep-types-migration.ts
@@ -0,0 +1,38 @@
+import is from '@sindresorhus/is';
+import type { PackageRule, PackageRuleInputConfig } from '../../types';
+import { AbstractMigration } from '../base/abstract-migration';
+
+interface DepTypesRule extends PackageRule, PackageRuleInputConfig {}
+
+export class DepTypesMigration extends AbstractMigration {
+  override readonly deprecated = true;
+  override readonly propertyName =
+    /^(?:(?:d|devD|optionalD|peerD)ependencies|engines|depTypes)$/;
+
+  override run(value: unknown, key: string): void {
+    const packageRules: PackageRule[] = this.get('packageRules') ?? [];
+    if (is.nonEmptyObject(value) && !is.array(value)) {
+      packageRules.push({
+        matchDepTypes: [key],
+        ...value,
+      } as PackageRule);
+    }
+
+    if (is.array(value)) {
+      for (const depType of value as DepTypesRule[]) {
+        if (is.object(depType) && !is.array(depType)) {
+          const depTypeName = depType.depType;
+          if (depTypeName) {
+            delete depType.depType;
+            depType.matchDepTypes = [depTypeName];
+            packageRules.push({ ...(depType as PackageRule) });
+          }
+        }
+      }
+    }
+
+    if (packageRules.length) {
+      this.setHard('packageRules', packageRules);
+    }
+  }
+}
diff --git a/lib/config/migrations/migrations-service.ts b/lib/config/migrations/migrations-service.ts
index 50e139fd1404de17b13d7a3b33538edd8f6bdb1f..0ded6715208a15667a0d13aaa68329dbfcea9713 100644
--- a/lib/config/migrations/migrations-service.ts
+++ b/lib/config/migrations/migrations-service.ts
@@ -15,6 +15,7 @@ import { BranchNameMigration } from './custom/branch-name-migration';
 import { BranchPrefixMigration } from './custom/branch-prefix-migration';
 import { CompatibilityMigration } from './custom/compatibility-migration';
 import { ComposerIgnorePlatformReqsMigration } from './custom/composer-ignore-platform-reqs-migration';
+import { DepTypesMigration } from './custom/dep-types-migration';
 import { DryRunMigration } from './custom/dry-run-migration';
 import { EnabledManagersMigration } from './custom/enabled-managers-migration';
 import { ExtendsMigration } from './custom/extends-migration';
@@ -131,6 +132,7 @@ export class MigrationsService {
     DryRunMigration,
     RequireConfigMigration,
     PackageFilesMigration,
+    DepTypesMigration,
     PackageRulesMigration,
     NodeMigration,
     SemanticPrefixMigration,