 diff --git a/MODULE.bazel b/MODULE.bazel
index 77e727584..0bca5e2be 100644
--- a/MODULE.bazel
+++ b/MODULE.bazel
@@ -16,9 +16,10 @@ bazel_dep(name = "bazel_skylib", version = "1.4.1")
 bazel_dep(name = "jsoncpp", version = "1.9.5")
 bazel_dep(name = "rules_cc", version = "0.0.9")
 bazel_dep(name = "rules_java", version = "4.0.0")
-bazel_dep(name = "rules_jvm_external", version = "5.1")
+bazel_dep(name = "rules_jvm_external", version = "6.7")
 bazel_dep(name = "rules_pkg", version = "0.7.0")
 bazel_dep(name = "rules_python", version = "0.10.2")
+bazel_dep(name = "rules_shell", version = "0.2.0")
 bazel_dep(name = "platforms", version = "0.0.8")
 bazel_dep(name = "zlib", version = "1.2.11")

diff --git a/build_defs/internal_shell.bzl b/build_defs/internal_shell.bzl
index 91628a5e5..d15cf29fb 100644
--- a/build_defs/internal_shell.bzl
+++ b/build_defs/internal_shell.bzl
@@ -3,6 +3,9 @@ Internal tools to migrate shell commands to Bazel as an intermediate step
 to wider Bazelification.
 """

+load("@rules_shell//shell:sh_binary.bzl", "sh_binary")
+load("@rules_shell//shell:sh_test.bzl", "sh_test")
+
 def inline_sh_binary(
         name,
         srcs = [],
@@ -41,7 +44,7 @@ def inline_sh_binary(
         testonly = kwargs["testonly"] if "testonly" in kwargs else None,
     )

-    native.sh_binary(
+    sh_binary(
         name = name,
         srcs = [name + "_genrule"],
         data = srcs + tools + deps,
@@ -86,7 +89,7 @@ def inline_sh_test(
         testonly = kwargs["testonly"] if "testonly" in kwargs else None,
     )

-    native.sh_test(
+    sh_test(
         name = name,
         srcs = [name + "_genrule"],
         data = srcs + tools + deps,
diff --git a/conformance/defs.bzl b/conformance/defs.bzl
index 8daef8650..a2dfdac21 100644
--- a/conformance/defs.bzl
+++ b/conformance/defs.bzl
@@ -3,6 +3,8 @@
 PLEASE DO NOT DEPEND ON THE CONTENTS OF THIS FILE, IT IS UNSTABLE.
 """

+load("@rules_shell//shell:sh_test.bzl", "sh_test")
+
 def conformance_test(
         name,
         testee,
@@ -28,7 +30,7 @@ def conformance_test(
         args = args + ["--text_format_failure_list %s" % _strip_bazel(text_format_failure_list)]
         failure_lists = failure_lists + [text_format_failure_list]

-    native.sh_test(
+    sh_test(
         name = name,
         srcs = ["//conformance:bazel_conformance_test_runner.sh"],
         data = [testee] + failure_lists + [
diff --git a/java/BUILD.bazel b/java/BUILD.bazel
index 14838ae37..1fdcff452 100644
--- a/java/BUILD.bazel
+++ b/java/BUILD.bazel
@@ -1,4 +1,5 @@
 load("@rules_pkg//:mappings.bzl", "pkg_filegroup", "pkg_files", "strip_prefix")
+load("@rules_shell//shell:sh_test.bzl", "sh_test")

 # Run Linkage Monitor
 sh_test(
diff --git a/java/core/BUILD.bazel b/java/core/BUILD.bazel
index 32df3e02e..25a075424 100644
--- a/java/core/BUILD.bazel
+++ b/java/core/BUILD.bazel
@@ -1,4 +1,5 @@
 load("@bazel_skylib//rules:build_test.bzl", "build_test")
+load("@rules_java//java:java_library.bzl", "java_library")
 load("@rules_java//java:defs.bzl", "java_lite_proto_library", "java_proto_library")
 load("@rules_pkg//:mappings.bzl", "pkg_files", "strip_prefix")
 load("@rules_proto//proto:defs.bzl", "proto_lang_toolchain", "proto_library")
diff --git a/java/internal/testing.bzl b/java/internal/testing.bzl
index b2a781bab..48c763f34 100644
--- a/java/internal/testing.bzl
+++ b/java/internal/testing.bzl
@@ -2,6 +2,9 @@
 Generates a side-car JUnit suite test runner class for each
 input src.
 """
+
+load("@rules_java//java:defs.bzl", "java_library", "java_test")
+
 _template = """import org.junit.runners.Suite;
 import org.junit.runner.RunWith;

@@ -36,7 +39,7 @@ _gen_suite = rule(

 def junit_tests(name, srcs, data = [], deps = [], package_name = "com.google.protobuf", test_prefix = None, **kwargs):
     testlib_name = "%s_lib" % name
-    native.java_library(
+    java_library(
         name = testlib_name,
         srcs = srcs,
         deps = deps,
@@ -59,7 +62,7 @@ def junit_tests(name, srcs, data = [], deps = [], package_name = "com.google.pro
             package_name = package_name,
             outname = suite_name,
         )
-        native.java_test(
+        java_test(
             name = test_name,
             test_class = suite_name,
             srcs = [src] + [":" + suite_name],
diff --git a/upb/cmake/build_defs.bzl b/upb/cmake/build_defs.bzl
index 325189c7f..c7a7a4558 100644
--- a/upb/cmake/build_defs.bzl
+++ b/upb/cmake/build_defs.bzl
@@ -7,6 +7,8 @@

 """Bazel support functions related to CMake support."""

+load("@rules_python//python:py_test.bzl", "py_test")
+
 def staleness_test(name, outs, generated_pattern, target_files = None, tags = [], **kwargs):
     """Tests that checked-in file(s) match the contents of generated file(s).

@@ -46,7 +48,7 @@ def staleness_test(name, outs, generated_pattern, target_files = None, tags = []
               "sed -i.bak -e 's|INSERT_FILE_LIST_HERE|" + "\\\n  ".join(file_list) + "|' $@",
     )

-    native.py_test(
+    py_test(
         name = name,
         srcs = [script_name],
         data = existing_outs + [generated_pattern % file for file in outs],
