diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
index 094b76dc7164..b4fe9ed7021a 100644
--- a/include/linux/lsm_hook_defs.h
+++ b/include/linux/lsm_hook_defs.h
@@ -396,6 +396,7 @@ LSM_HOOK(void, LSM_RET_VOID, audit_rule_free, void *lsmrule)
 LSM_HOOK(int, 0, bpf, int cmd, union bpf_attr *attr, unsigned int size)
 LSM_HOOK(int, 0, bpf_map, struct bpf_map *map, fmode_t fmode)
 LSM_HOOK(int, 0, bpf_prog, struct bpf_prog *prog)
+LSM_HOOK(int, 0, bpf_map_create_security, const union bpf_attr *attr)
 LSM_HOOK(int, 0, bpf_map_alloc_security, struct bpf_map *map)
 LSM_HOOK(void, LSM_RET_VOID, bpf_map_free_security, struct bpf_map *map)
 LSM_HOOK(int, 0, bpf_prog_alloc_security, struct bpf_prog_aux *aux)
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 6e156d2acffc..42bf7c0aa4d8 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -1598,6 +1598,18 @@
  *	@prog: bpf prog that userspace want to use.
  *	Return 0 if permission is granted.
  *
+ * @bpf_map_create_security:
+ *	Do a check to determine permission to create requested BPF map.
+ *	Implementation can override kernel capabilities checks according to
+ *	the rules below:
+ *	  - 0 should be returned to delegate permission checks to other
+ *	    installed LSM callbacks and/or hard-wired kernel logic, which
+ *	    would enforce CAP_BPF/CAP_NET_ADMIN capabilities;
+ *	  - reject BPF map creation by returning -EPERM or any other
+ *	    negative error code;
+ *	  - allow BPF map creation, overriding kernel checks, by returning
+ *	    a positive result.
+ *
  * @bpf_map_alloc_security:
  *	Initialize the security field inside bpf map.
  *	Return 0 on success, error on failure.
diff --git a/include/linux/security.h b/include/linux/security.h
index 5984d0d550b4..e5374fe92ef6 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -2023,6 +2023,7 @@ struct bpf_prog_aux;
 extern int security_bpf(int cmd, union bpf_attr *attr, unsigned int size);
 extern int security_bpf_map(struct bpf_map *map, fmode_t fmode);
 extern int security_bpf_prog(struct bpf_prog *prog);
+extern int security_bpf_map_create(const union bpf_attr *attr);
 extern int security_bpf_map_alloc(struct bpf_map *map);
 extern void security_bpf_map_free(struct bpf_map *map);
 extern int security_bpf_prog_alloc(struct bpf_prog_aux *aux);
@@ -2044,6 +2045,11 @@ static inline int security_bpf_prog(struct bpf_prog *prog)
 	return 0;
 }
 
+static inline int security_bpf_map_create(const union bpf_attr *attr)
+{
+	return 0;
+}
+
 static inline int security_bpf_map_alloc(struct bpf_map *map)
 {
 	return 0;
diff --git a/kernel/bpf/bpf_lsm.c b/kernel/bpf/bpf_lsm.c
index e14c822f8911..931d4dda5dac 100644
--- a/kernel/bpf/bpf_lsm.c
+++ b/kernel/bpf/bpf_lsm.c
@@ -260,6 +260,7 @@ bpf_lsm_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
 BTF_SET_START(sleepable_lsm_hooks)
 BTF_ID(func, bpf_lsm_bpf)
 BTF_ID(func, bpf_lsm_bpf_map)
+BTF_ID(func, bpf_lsm_bpf_map_create_security)
 BTF_ID(func, bpf_lsm_bpf_map_alloc_security)
 BTF_ID(func, bpf_lsm_bpf_map_free_security)
 BTF_ID(func, bpf_lsm_bpf_prog)
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index cbea4999e92f..7d1165814efc 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -980,7 +980,7 @@ int map_check_no_btf(const struct bpf_map *map,
 }
 
 static int map_check_btf(struct bpf_map *map, const struct btf *btf,
-			 u32 btf_key_id, u32 btf_value_id)
+			 u32 btf_key_id, u32 btf_value_id, bool priv_checked)
 {
 	const struct btf_type *key_type, *value_type;
 	u32 key_size, value_size;
@@ -1008,7 +1008,7 @@ static int map_check_btf(struct bpf_map *map, const struct btf *btf,
 	if (!IS_ERR_OR_NULL(map->record)) {
 		int i;
 
-		if (!bpf_capable()) {
+		if (!priv_checked && !bpf_capable()) {
 			ret = -EPERM;
 			goto free_map_tab;
 		}
@@ -1097,10 +1097,12 @@ static int map_create(union bpf_attr *attr)
 	int numa_node = bpf_map_attr_numa_node(attr);
 	u32 map_type = attr->map_type;
 	struct btf_field_offs *foffs;
+	bool priv_checked = false;
 	struct bpf_map *map;
 	int f_flags;
 	int err;
 
+	/* sanity checks */
 	err = CHECK_ATTR(BPF_MAP_CREATE);
 	if (err)
 		return -EINVAL;
@@ -1145,6 +1147,15 @@ static int map_create(union bpf_attr *attr)
 	if (!ops->map_mem_usage)
 		return -EINVAL;
 
+	/* security checks */
+	err = security_bpf_map_create(attr);
+	if (err < 0)
+		return err;
+	if (err > 0) {
+		priv_checked = true;
+		goto skip_priv_checks;
+	}
+
 	/* Intent here is for unprivileged_bpf_disabled to block key object
 	 * creation commands for unprivileged users; other actions depend
 	 * of fd availability and access to bpffs, so are dependent on
@@ -1203,6 +1214,8 @@ static int map_create(union bpf_attr *attr)
 		return -EPERM;
 	}
 
+skip_priv_checks:
+	/* create and init map */
 	map = ops->map_alloc(attr);
 	if (IS_ERR(map))
 		return PTR_ERR(map);
@@ -1243,7 +1256,7 @@ static int map_create(union bpf_attr *attr)
 
 		if (attr->btf_value_type_id) {
 			err = map_check_btf(map, btf, attr->btf_key_type_id,
-					    attr->btf_value_type_id);
+					    attr->btf_value_type_id, priv_checked);
 			if (err)
 				goto free_map;
 		}
diff --git a/security/security.c b/security/security.c
index cf6cc576736f..f9b885680966 100644
--- a/security/security.c
+++ b/security/security.c
@@ -2682,6 +2682,10 @@ int security_bpf_prog(struct bpf_prog *prog)
 {
 	return call_int_hook(bpf_prog, 0, prog);
 }
+int security_bpf_map_create(const union bpf_attr *attr)
+{
+	return call_int_hook(bpf_map_create_security, 0, attr);
+}
 int security_bpf_map_alloc(struct bpf_map *map)
 {
 	return call_int_hook(bpf_map_alloc_security, 0, map);
