diff --git a/lib/modules/manager/bazel/parser.spec.ts b/lib/modules/manager/bazel/parser.spec.ts
index 7c0de48a14a874335ad02bf34b344f6a9daaf0f6..3f7075bda638e02081255dc3e61cedd7ecc7c1b8 100644
--- a/lib/modules/manager/bazel/parser.spec.ts
+++ b/lib/modules/manager/bazel/parser.spec.ts
@@ -218,4 +218,44 @@ describe('modules/manager/bazel/parser', () => {
       },
     ]);
   });
+
+  it('parses Maven', () => {
+    const input = codeBlock`
+      maven_install(
+        artifacts = [
+          "com.example1:foo:1.1.1",
+          maven.artifact(
+            group = "com.example2",
+            artifact = "bar",
+            version = "2.2.2",
+          )
+        ],
+        repositories = [
+          "https://example1.com/maven2",
+          "https://example2.com/maven2",
+        ]
+      )
+    `;
+
+    const res = parse(input);
+
+    expect(res?.map(extract)).toEqual([
+      {
+        rule: 'maven_install',
+        artifacts: [
+          'com.example1:foo:1.1.1',
+          {
+            _function: 'maven.artifact',
+            artifact: 'bar',
+            group: 'com.example2',
+            version: '2.2.2',
+          },
+        ],
+        repositories: [
+          'https://example1.com/maven2',
+          'https://example2.com/maven2',
+        ],
+      },
+    ]);
+  });
 });
diff --git a/lib/modules/manager/bazel/parser.ts b/lib/modules/manager/bazel/parser.ts
index 776f38673d3c0e599a7e23654732f1737196fd20..c6a8f77828cb7f827214ae7f946de94c9ed8c75a 100644
--- a/lib/modules/manager/bazel/parser.ts
+++ b/lib/modules/manager/bazel/parser.ts
@@ -10,6 +10,7 @@ interface Ctx {
   results: RecordFragment[];
   stack: NestedFragment[];
   recordKey?: string;
+  subRecordKey?: string;
 }
 
 function emptyCtx(source: string): Ctx {
@@ -45,9 +46,20 @@ function extractTreeValue(
  * - `tag = "1.2.3"`
  * - `name = "foobar"`
  * - `deps = ["foo", "bar"]`
+ * - `
+ *     artifacts = [
+         maven.artifact(
+           group = "com.example1",
+           artifact = "foobar",
+           version = "1.2.3",
+         )
+       ]
+     `
  **/
 const kwParams = q
-  .sym<Ctx>((ctx, { value: recordKey }) => ({ ...ctx, recordKey }))
+  .sym<Ctx>((ctx, { value: recordKey }) => {
+    return { ...ctx, recordKey };
+  })
   .op('=')
   .alt(
     // string
@@ -59,10 +71,12 @@ const kwParams = q
       }
       return ctx;
     }),
-    // array of strings
+    // array of strings or calls
     q.tree({
       type: 'wrapped-tree',
       maxDepth: 1,
+      startsWith: '[',
+      endsWith: ']',
       preHandler: (ctx, tree) => {
         const parentRecord = currentFragment(ctx) as RecordFragment;
         if (
@@ -80,17 +94,93 @@ const kwParams = q
         }
         return ctx;
       },
-      search: q.str<Ctx>((ctx, { value, offset }) => {
-        const parentRecord = currentFragment(ctx);
-        if (parentRecord.type === 'record' && ctx.recordKey) {
-          const key = ctx.recordKey;
-          const array = parentRecord.children[key];
-          if (array.type === 'array') {
-            array.children.push({ type: 'string', value, offset });
+      search: q.alt(
+        q.str<Ctx>((ctx, { value, offset }) => {
+          const parentRecord = currentFragment(ctx);
+          if (parentRecord.type === 'record' && ctx.recordKey) {
+            const key = ctx.recordKey;
+            const array = parentRecord.children[key];
+            if (array.type === 'array') {
+              array.children.push({ type: 'string', value, offset });
+            }
           }
-        }
-        return ctx;
-      }),
+          return ctx;
+        }),
+        q
+          .sym<Ctx>()
+          .handler(recordStartHandler)
+          .handler((ctx, { value, offset }) => {
+            const ruleFragment = currentFragment(ctx);
+            if (ruleFragment.type === 'record') {
+              ruleFragment.children._function = {
+                type: 'string',
+                value,
+                offset,
+              };
+            }
+            return ctx;
+          })
+          .many(
+            q.op<Ctx>('.').sym((ctx, { value }) => {
+              const ruleFragment = currentFragment(ctx);
+              if (
+                ruleFragment.type === 'record' &&
+                ruleFragment.children._function
+              ) {
+                ruleFragment.children._function.value += `.${value}`;
+              }
+              return ctx;
+            }),
+            0,
+            3
+          )
+          .tree({
+            type: 'wrapped-tree',
+            maxDepth: 1,
+            startsWith: '(',
+            endsWith: ')',
+            search: q
+              .sym<Ctx>((ctx, { value: subRecordKey }) => ({
+                ...ctx,
+                subRecordKey,
+              }))
+              .op('=')
+              .str((ctx, { value: subRecordValue, offset }) => {
+                const subRecordKey = ctx.subRecordKey!;
+                const ruleFragment = currentFragment(ctx);
+                if (ruleFragment.type === 'record') {
+                  ruleFragment.children[subRecordKey] = {
+                    type: 'string',
+                    value: subRecordValue,
+                    offset,
+                  };
+                }
+                delete ctx.subRecordKey;
+                return ctx;
+              }),
+            postHandler: (ctx, tree) => {
+              const callFrag = currentFragment(ctx);
+              ctx.stack.pop();
+              if (callFrag.type === 'record' && tree.type === 'wrapped-tree') {
+                callFrag.value = extractTreeValue(
+                  ctx.source,
+                  tree,
+                  callFrag.offset
+                );
+
+                const parentRecord = currentFragment(ctx);
+                if (parentRecord.type === 'record' && ctx.recordKey) {
+                  const key = ctx.recordKey;
+                  const array = parentRecord.children[key];
+                  if (array.type === 'array') {
+                    array.children.push(callFrag);
+                  }
+                }
+              }
+              return ctx;
+            },
+          })
+      ),
       postHandler: (ctx, tree) => {
         const parentRecord = currentFragment(ctx);
         if (
@@ -140,7 +230,7 @@ function ruleCall(
   });
 }
 
-function ruleStartHandler(ctx: Ctx, { offset }: lexer.Token): Ctx {
+function recordStartHandler(ctx: Ctx, { offset }: lexer.Token): Ctx {
   ctx.stack.push({
     type: 'record',
     value: '',
@@ -166,7 +256,7 @@ function ruleNameHandler(ctx: Ctx, { value, offset }: lexer.Token): Ctx {
  */
 const regularRule = q
   .sym<Ctx>(supportedRulesRegex, (ctx, token) =>
-    ruleNameHandler(ruleStartHandler(ctx, token), token)
+    ruleNameHandler(recordStartHandler(ctx, token), token)
   )
   .join(ruleCall(kwParams));
 
@@ -176,7 +266,7 @@ const regularRule = q
  * - `maybe(go_repository, ...)`
  */
 const maybeRule = q
-  .sym<Ctx>('maybe', ruleStartHandler)
+  .sym<Ctx>('maybe', recordStartHandler)
   .join(
     ruleCall(
       q.alt(
diff --git a/lib/modules/manager/bazel/rules/index.spec.ts b/lib/modules/manager/bazel/rules/index.spec.ts
index c133e7a4f869eca633cb3276a68fd620757a63b5..761222f6eabfb484357ee3c3f1f752f9803d08fb 100644
--- a/lib/modules/manager/bazel/rules/index.spec.ts
+++ b/lib/modules/manager/bazel/rules/index.spec.ts
@@ -348,4 +348,48 @@ describe('modules/manager/bazel/rules/index', () => {
       ]);
     });
   });
+
+  describe('maven', () => {
+    it('extracts maven dependencies', () => {
+      expect(
+        extractDepsFromFragmentData({
+          rule: 'maven_install',
+          artifacts: [
+            'com.example1:foo:1.1.1',
+            {
+              artifact: 'bar',
+              function: 'maven.artifact',
+              group: 'com.example2',
+              version: '2.2.2',
+            },
+          ],
+          repositories: [
+            'https://example1.com/maven2',
+            'https://example2.com/maven2',
+          ],
+        })
+      ).toEqual([
+        {
+          currentValue: '1.1.1',
+          datasource: 'maven',
+          depType: 'maven_install',
+          depName: 'com.example1:foo',
+          registryUrls: [
+            'https://example1.com/maven2',
+            'https://example2.com/maven2',
+          ],
+        },
+        {
+          currentValue: '2.2.2',
+          datasource: 'maven',
+          depType: 'maven_install',
+          depName: 'com.example2:bar',
+          registryUrls: [
+            'https://example1.com/maven2',
+            'https://example2.com/maven2',
+          ],
+        },
+      ]);
+    });
+  });
 });
diff --git a/lib/modules/manager/bazel/rules/index.ts b/lib/modules/manager/bazel/rules/index.ts
index 149ff09e742ce57672609bb24ba70f685204f178..3fa644cad51050a715ac7e10ff52705f63d3a0d6 100644
--- a/lib/modules/manager/bazel/rules/index.ts
+++ b/lib/modules/manager/bazel/rules/index.ts
@@ -6,14 +6,27 @@ import { DockerTarget, dockerRules } from './docker';
 import { GitTarget, gitRules } from './git';
 import { GoTarget, goRules } from './go';
 import { HttpTarget, httpRules } from './http';
+import { MavenTarget, mavenRules } from './maven';
 
-const Target = z.union([DockerTarget, GitTarget, GoTarget, HttpTarget]);
+const Target = z.union([
+  DockerTarget,
+  GitTarget,
+  GoTarget,
+  HttpTarget,
+  MavenTarget,
+]);
 
 /**
  * Gather all rule names supported by Renovate in order to speed up parsing
  * by filtering out other syntactically correct rules we don't support yet.
  */
-const supportedRules = [...dockerRules, ...gitRules, ...goRules, ...httpRules];
+const supportedRules = [
+  ...dockerRules,
+  ...gitRules,
+  ...goRules,
+  ...httpRules,
+  ...mavenRules,
+];
 export const supportedRulesRegex = regEx(`^${supportedRules.join('|')}$`);
 
 export function extractDepsFromFragmentData(
diff --git a/lib/modules/manager/bazel/rules/maven.ts b/lib/modules/manager/bazel/rules/maven.ts
new file mode 100644
index 0000000000000000000000000000000000000000..82fcdd3934fa01e103d0413590ae5359f9ccb33e
--- /dev/null
+++ b/lib/modules/manager/bazel/rules/maven.ts
@@ -0,0 +1,51 @@
+import is from '@sindresorhus/is';
+import { z } from 'zod';
+import { MavenDatasource } from '../../../datasource/maven';
+import type { PackageDependency } from '../../types';
+
+export const mavenRules = ['maven_install'] as const;
+
+const ArtifactSpec = z.object({
+  group: z.string(),
+  artifact: z.string(),
+  version: z.string(),
+});
+type ArtifactSpec = z.infer<typeof ArtifactSpec>;
+
+export const MavenTarget = z
+  .object({
+    rule: z.enum(mavenRules),
+    artifacts: z
+      .union([z.string(), ArtifactSpec])
+      .array()
+      .transform((xs) => {
+        const result: ArtifactSpec[] = [];
+        for (const x of xs) {
+          if (is.string(x)) {
+            const [group, artifact, version] = x.split(':');
+            if (group && artifact && version) {
+              result.push({ group, artifact, version });
+            }
+          } else {
+            result.push(x);
+          }
+        }
+
+        return result;
+      }),
+    repositories: z.array(z.string()).optional(),
+  })
+  .transform(
+    ({
+      rule: depType,
+      artifacts,
+      repositories: registryUrls,
+    }): PackageDependency[] =>
+      artifacts.map(({ group, artifact, version: currentValue }) => ({
+        datasource: MavenDatasource.id,
+        depName: `${group}:${artifact}`,
+        currentValue,
+        depType,
+        registryUrls,
+      }))
+  );
diff --git a/lib/modules/manager/bazel/types.ts b/lib/modules/manager/bazel/types.ts
index ce1233b12f1aa77c2f0f01dbdb34b4fa705ffa81..ea94a32848bf1551cec586c796406c33067cd6d0 100644
--- a/lib/modules/manager/bazel/types.ts
+++ b/lib/modules/manager/bazel/types.ts
@@ -56,6 +56,7 @@ export type FragmentData =
 export type FragmentPath =
   | [number]
   | [number, string]
-  | [number, string, number];
+  | [number, string, number]
+  | [number, string, number, string];
 
 export type FragmentUpdater = string | ((_: string) => string);