diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 5da9bb0ac6a4..f2defbfd758e 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -4176,6 +4176,15 @@ struct mgmt_frame_regs {
 	u32 global_mcast_stypes, interface_mcast_stypes;
 };
 
+/**
+ * struct cfg80211_iface_usage - Notify about intended interface usage
+ *
+ * @types_mask: mask of interface types that are going to be used.
+ */
+struct cfg80211_iface_usage {
+	u32 types_mask;
+};
+
 /**
  * struct cfg80211_ops - backend description for wireless configuration
  *
@@ -4577,6 +4586,7 @@ struct mgmt_frame_regs {
  *
  * @set_hw_timestamp: Enable/disable HW timestamping of TM/FTM frames.
  * @set_ttlm: set the TID to link mapping.
+ * @iface_usage: notify about intended usage of added interfaces.
  */
 struct cfg80211_ops {
 	int	(*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -4938,6 +4948,8 @@ struct cfg80211_ops {
 				    struct cfg80211_set_hw_timestamp *hwts);
 	int	(*set_ttlm)(struct wiphy *wiphy, struct net_device *dev,
 			    struct cfg80211_ttlm_params *params);
+	void    (*iface_usage)(struct wiphy *wiphy, struct net_device *dev,
+			       struct cfg80211_iface_usage *usage);
 };
 
 /*
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index f917bc6c9b6f..92dbbb0589f0 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -1329,6 +1329,15 @@
  *      %NL80211_ATTR_MLO_TTLM_ULINK attributes are used to specify the
  *      TID to Link mapping for downlink/uplink traffic.
  *
+ * @NL80211_CMD_IFACE_USAGE_NOTIF: Notify kernel about the expected interface
+ *      usage. Allows user space to indicate to the kernel that it intends to
+ *      use the interface soon and what is the expected usage of the interface
+ *      so resources could be prepared etc. This is useful in case an added
+ *      interface is not going to be used immediately but soon, and its type
+ *      might change. The %NL80211_ATTR_IFACE_USAGE_IFTYPES attribute is used to
+ *      provide the mask of intended interface types (the current type must be
+ *      included in the mask).
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -1586,6 +1595,8 @@ enum nl80211_commands {
 
 	NL80211_CMD_SET_TID_TO_LINK_MAPPING,
 
+	NL80211_CMD_IFACE_USAGE_NOTIF,
+
 	/* add new commands above here */
 
 	/* used to define NL80211_CMD_MAX below */
@@ -2856,6 +2867,9 @@ enum nl80211_commands {
  *	%NL80211_CMD_ASSOCIATE indicating the SPP A-MSDUs
  *	are used on this connection
  *
+ * @NL80211_ATTR_IFACE_USAGE_IFTYPES: a bitmask of interface types that might be
+ *      used with the interface.
+ *
  * @NUM_NL80211_ATTR: total number of nl80211_attrs available
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
@@ -3401,6 +3415,8 @@ enum nl80211_attrs {
 
 	NL80211_ATTR_ASSOC_SPP_AMSDU,
 
+	NL80211_ATTR_IFACE_USAGE_IFTYPES,
+
 	/* add attributes here, update the policy in nl80211.c */
 
 	__NL80211_ATTR_AFTER_LAST,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 296acd2a2a1b..04110b74547d 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -825,6 +825,11 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
 	[NL80211_ATTR_MLO_TTLM_DLINK] = NLA_POLICY_EXACT_LEN(sizeof(u16) * 8),
 	[NL80211_ATTR_MLO_TTLM_ULINK] = NLA_POLICY_EXACT_LEN(sizeof(u16) * 8),
 	[NL80211_ATTR_ASSOC_SPP_AMSDU] = { .type = NLA_FLAG },
+
+	/* Set the limits to not allow NL80211_IFTYPE_UNSPECIFIED */
+	[NL80211_ATTR_IFACE_USAGE_IFTYPES] =
+		NLA_POLICY_RANGE(NLA_U32, BIT(NL80211_IFTYPE_UNSPECIFIED + 1),
+				 BIT(NUM_NL80211_IFTYPES) - 2),
 };
 
 /* policy for the key attributes */
@@ -16319,6 +16324,31 @@ nl80211_set_ttlm(struct sk_buff *skb, struct genl_info *info)
 	return rdev_set_ttlm(rdev, dev, &params);
 }
 
+static int
+nl80211_iface_usage(struct sk_buff *skb, struct genl_info *info)
+{
+	struct cfg80211_iface_usage iface_usage = {};
+	struct cfg80211_registered_device *rdev = info->user_ptr[0];
+	struct net_device *dev = info->user_ptr[1];
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+	/* once the interface is up and running its type can no longer change */
+	if (wdev_running(wdev))
+		return -EINVAL;
+
+	if (!info->attrs[NL80211_ATTR_IFACE_USAGE_IFTYPES])
+		return -EINVAL;
+
+	iface_usage.types_mask =
+		nla_get_u32(info->attrs[NL80211_ATTR_IFACE_USAGE_IFTYPES]);
+
+	if (!(BIT(wdev->iftype) & iface_usage.types_mask))
+		return -EINVAL;
+
+	rdev_iface_usage(rdev, dev, &iface_usage);
+	return 0;
+}
+
 #define NL80211_FLAG_NEED_WIPHY		0x01
 #define NL80211_FLAG_NEED_NETDEV	0x02
 #define NL80211_FLAG_NEED_RTNL		0x04
@@ -17511,6 +17541,12 @@ static const struct genl_small_ops nl80211_small_ops[] = {
 		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP),
 	},
+	{
+		.cmd = NL80211_CMD_IFACE_USAGE_NOTIF,
+		.doit = nl80211_iface_usage,
+		.flags = GENL_UNS_ADMIN_PERM,
+		.internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV),
+	},
 };
 
 static struct genl_family nl80211_fam __ro_after_init = {
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
index 43897a5269b6..0a13212d9c8d 100644
--- a/net/wireless/rdev-ops.h
+++ b/net/wireless/rdev-ops.h
@@ -1542,4 +1542,17 @@ rdev_set_ttlm(struct cfg80211_registered_device *rdev,
 
 	return ret;
 }
+
+static inline void
+rdev_iface_usage(struct cfg80211_registered_device *rdev,
+		 struct net_device *dev,
+		 struct cfg80211_iface_usage *iface_usage)
+{
+	struct wiphy *wiphy = &rdev->wiphy;
+
+	trace_rdev_iface_usage(wiphy, dev, iface_usage);
+	if (rdev->ops->iface_usage)
+		rdev->ops->iface_usage(wiphy, dev, iface_usage);
+	trace_rdev_return_void(wiphy);
+}
 #endif /* __CFG80211_RDEV_OPS */
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index 14cfa0aba93a..2f5df52918cf 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -3032,6 +3032,24 @@ TRACE_EVENT(rdev_set_ttlm,
 		  WIPHY_PR_ARG, NETDEV_PR_ARG)
 );
 
+TRACE_EVENT(rdev_iface_usage,
+	TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+		 struct cfg80211_iface_usage *iface_usage),
+	TP_ARGS(wiphy, netdev, iface_usage),
+	TP_STRUCT__entry(
+		WIPHY_ENTRY
+		NETDEV_ENTRY
+		__field(u32, types_mask)
+	),
+	TP_fast_assign(
+		WIPHY_ASSIGN;
+		NETDEV_ASSIGN;
+		__entry->types_mask = iface_usage->types_mask;
+	),
+	TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", types_mask=0x%x",
+		  WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->types_mask)
+);
+
 /*************************************************************
  *	     cfg80211 exported functions traces		     *
  *************************************************************/
