diff --git a/private/bpfloader.te b/private/bpfloader.te
index 83a74a20977345de0bbc63026412b15f7329d8de..f8da1eba3433267f745bb2a2b22f43535ed12868 100644
--- a/private/bpfloader.te
+++ b/private/bpfloader.te
@@ -3,11 +3,6 @@ type bpfloader, domain;
 type bpfloader_exec, system_file_type, exec_type, file_type;
 typeattribute bpfloader coredomain;
 
-# Process need CAP_NET_ADMIN to run bpf programs as cgroup filter
-allow bpfloader self:global_capability_class_set net_admin;
-
-r_dir_file(bpfloader, cgroup_bpf)
-
 # These permission is required for pin bpf program for netd.
 allow bpfloader fs_bpf:dir  create_dir_perms;
 allow bpfloader fs_bpf:file create_file_perms;
@@ -15,9 +10,9 @@ allow bpfloader devpts:chr_file { read write };
 
 allow bpfloader netd:fd use;
 
-# Use pinned bpf map files from netd.
-allow bpfloader netd:bpf { map_read map_write };
-allow bpfloader self:bpf { prog_load prog_run };
+# Allow bpfloader to create bpf maps and programs. The map_read and map_write permission is needed
+# for retrieving a pinned map when bpfloader do a run time restart.
+allow bpfloader self:bpf { prog_load prog_run map_read map_write map_create };
 
 dontaudit bpfloader self:global_capability_class_set sys_admin;
 
@@ -29,7 +24,7 @@ neverallow { domain -bpfloader -netd -netutils_wrapper} *:bpf prog_run;
 neverallow { domain -netd -bpfloader } bpfloader_exec:file { execute execute_no_trans };
 neverallow bpfloader domain:{ tcp_socket udp_socket rawip_socket } *;
 # only system_server, netd and bpfloader can read/write the bpf maps
-neverallow { domain -system_server -netd -bpfloader} netd:bpf { map_read map_write };
+neverallow { domain -system_server -netd -bpfloader} *:bpf { map_read map_write };
 
 # No domain should be allowed to ptrace bpfloader
 neverallow { domain userdebug_or_eng(`-llkd') } bpfloader:process ptrace;
diff --git a/private/netd.te b/private/netd.te
index 281105d04fd76c181b581a0c116ef03ef5bd306b..711d569a0788cced016f786bd741898347814dd0 100644
--- a/private/netd.te
+++ b/private/netd.te
@@ -11,5 +11,6 @@ domain_auto_trans(netd, clatd_exec, clatd)
 # Allow netd to start bpfloader_exec in its own domain
 domain_auto_trans(netd, bpfloader_exec, bpfloader)
 
-# give netd permission to setup iptables rule with xt_bpf
-allow netd bpfloader:bpf prog_run;
+# give netd permission to setup iptables rule with xt_bpf, attach program to cgroup, and read/write
+# the map created by bpfloader
+allow netd bpfloader:bpf { prog_run map_read map_write };
diff --git a/private/system_server.te b/private/system_server.te
index 4581417a5552e93887111f64f51f748c7fe8ede7..ccc2017dff761ab7d2ea2348d968b1e4bdb57715 100644
--- a/private/system_server.te
+++ b/private/system_server.te
@@ -846,7 +846,7 @@ with_asan(`
 # the map after snapshot is recorded
 allow system_server fs_bpf:dir search;
 allow system_server fs_bpf:file read;
-allow system_server netd:bpf map_read;
+allow system_server bpfloader:bpf map_read;
 
 # ART Profiles.
 # Allow system_server to open profile snapshots for read.
diff --git a/public/netd.te b/public/netd.te
index 10f1959972d69565b407ae9b3a1c89045fbc8c32..39864f69d0bdc8b009d3162a1a31ae61099d50da 100644
--- a/public/netd.te
+++ b/public/netd.te
@@ -55,6 +55,8 @@ allow netd sysfs_net:file w_file_perms;
 # TODO: added to match above sysfs rule. Remove me?
 allow netd sysfs_usb:file write;
 
+r_dir_file(netd, cgroup_bpf)
+
 allow netd fs_bpf:dir  create_dir_perms;
 allow netd fs_bpf:file create_file_perms;
 
@@ -105,9 +107,6 @@ allow netd netdomain:fd use;
 # give netd permission to read and write netlink xfrm
 allow netd self:netlink_xfrm_socket { create_socket_perms_no_ioctl nlmsg_write nlmsg_read };
 
-# give netd permission to use eBPF functionalities
-allow netd self:bpf { map_create map_read map_write };
-
 # Allow netd to register as hal server.
 add_hwservice(netd, system_net_netd_hwservice)
 hwbinder_use(netd)