diff --git a/include/net/mac802154.h b/include/net/mac802154.h
index 9b852c02db88..f73b4f4f1025 100644
--- a/include/net/mac802154.h
+++ b/include/net/mac802154.h
@@ -213,6 +213,17 @@ enum ieee802154_hw_flags {
  * exit_scan_mode
  *	  Exits the scan mode and returns to a fully functioning state.
  *	  Should only be provided if ->enter_scan_mode() is populated.
+ *
+ * enter_beacons_mode
+ *	  Enters the beacons mode, the stack will either send beacons at a fixed
+ *	  rate or upon request depending on the configuration.
+ *	  Can be NULL, if the driver has no internal configuration to do.
+ *	  Returns either zero, or negative errno.
+ *
+ * exit_beacons_mode
+ *	  Exits the beacons mode and returns to a fully functioning state.
+ *	  Should only be provided if ->enter_beacons_mode() is populated.
+ *	  Returns either zero, or negative errno.
  */
 struct ieee802154_ops {
 	struct module	*owner;
@@ -242,6 +253,9 @@ struct ieee802154_ops {
 	int		(*enter_scan_mode)(struct ieee802154_hw *hw,
 					   struct cfg802154_scan_request *request);
 	void		(*exit_scan_mode)(struct ieee802154_hw *hw);
+	int		(*enter_beacons_mode)(struct ieee802154_hw *hw,
+					      struct cfg802154_beacons_request *request);
+	void		(*exit_beacons_mode)(struct ieee802154_hw *hw);
 };
 
 /**
diff --git a/net/mac802154/driver-ops.h b/net/mac802154/driver-ops.h
index 9da2325d8346..fa874088a284 100644
--- a/net/mac802154/driver-ops.h
+++ b/net/mac802154/driver-ops.h
@@ -311,4 +311,33 @@ static inline void drv_exit_scan_mode(struct ieee802154_local *local)
 	trace_802154_drv_return_void(local);
 }
 
+static inline int drv_enter_beacons_mode(struct ieee802154_local *local,
+					 struct cfg802154_beacons_request *request)
+{
+	int ret;
+
+	might_sleep();
+
+	if (!local->ops->enter_beacons_mode || !local->ops->exit_beacons_mode)
+		return 0;
+
+	trace_802154_drv_enter_beacons_mode(local, request);
+	ret = local->ops->enter_beacons_mode(&local->hw, request);
+	trace_802154_drv_return_int(local, ret);
+
+	return ret;
+}
+
+static inline void drv_exit_beacons_mode(struct ieee802154_local *local)
+{
+	might_sleep();
+
+	if (!local->ops->enter_beacons_mode || !local->ops->exit_beacons_mode)
+		return;
+
+	trace_802154_drv_exit_beacons_mode(local);
+	local->ops->exit_beacons_mode(&local->hw);
+	trace_802154_drv_return_void(local);
+}
+
 #endif /* __MAC802154_DRIVER_OPS */
diff --git a/net/mac802154/scan.c b/net/mac802154/scan.c
index a639c53fa3ba..bda13448e294 100644
--- a/net/mac802154/scan.c
+++ b/net/mac802154/scan.c
@@ -122,6 +122,7 @@ int mac802154_send_beacons_locked(struct ieee802154_sub_if_data *sdata,
 				  struct cfg802154_beacons_request *request)
 {
 	struct ieee802154_local *local = sdata->local;
+	int ret;
 
 	lockdep_assert_held(&local->beacons_lock);
 
@@ -130,6 +131,13 @@ int mac802154_send_beacons_locked(struct ieee802154_sub_if_data *sdata,
 
 	local->ongoing_beacons_request = true;
 
+	/* Either let the hardware handle the beacons or handle them manually */
+	ret = drv_enter_beacons_mode(local, request);
+	if (ret) {
+		local->ongoing_beacons_request = false;
+		return ret;
+	}
+
 	memset(&local->beacon, 0, sizeof(local->beacon));
 	local->beacon.mhr.fc.type = IEEE802154_BEACON_FRAME;
 	local->beacon.mhr.fc.security_enabled = 0;
@@ -179,6 +187,8 @@ int mac802154_stop_beacons_locked(struct ieee802154_local *local)
 	if (local->beacons_interval >= 0)
 		cancel_delayed_work(&local->beacons_work);
 
+	drv_exit_beacons_mode(local);
+
 	return 0;
 }
 
diff --git a/net/mac802154/trace.h b/net/mac802154/trace.h
index 9c0a4f07ced1..93519181045a 100644
--- a/net/mac802154/trace.h
+++ b/net/mac802154/trace.h
@@ -292,6 +292,27 @@ DEFINE_EVENT(local_only_evt4, 802154_drv_exit_scan_mode,
 	TP_ARGS(local)
 );
 
+TRACE_EVENT(802154_drv_enter_beacons_mode,
+	TP_PROTO(struct ieee802154_local *local,
+		 struct cfg802154_beacons_request *request),
+	TP_ARGS(local, request),
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		__field(u8, interval)
+	),
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		__entry->interval = request->interval;
+	),
+	TP_printk(LOCAL_PR_FMT ", send beacons at interval: %d",
+		  LOCAL_PR_ARG, __entry->interval)
+);
+
+DEFINE_EVENT(local_only_evt4, 802154_drv_exit_beacons_mode,
+	TP_PROTO(struct ieee802154_local *local),
+	TP_ARGS(local)
+);
+
 #endif /* !__MAC802154_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */
 
 #undef TRACE_INCLUDE_PATH
