diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
index d9426b01f462..92c1de636128 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -161,6 +161,23 @@ static const char * const mtk_clks_source_name[] = {
 	"sgmii_ck", "eth2pll", "wocpu0", "wocpu1", "netsys0", "netsys1"
 };
 
+static DECLARE_NETDEV_FEATURE_SET(mtk_hw_feature_set,
+				  NETIF_F_IP_CSUM_BIT,
+				  NETIF_F_RXCSUM_BIT,
+				  NETIF_F_HW_VLAN_CTAG_TX_BIT,
+				  NETIF_F_HW_VLAN_CTAG_RX_BIT,
+				  NETIF_F_SG_BIT,
+				  NETIF_F_TSO_BIT,
+				  NETIF_F_TSO6_BIT,
+				  NETIF_F_IPV6_CSUM_BIT,
+				  NETIF_F_HW_TC_BIT);
+static DECLARE_NETDEV_FEATURE_SET(mtk_mt7628_hw_feature_set,
+				  NETIF_F_SG_BIT,
+				  NETIF_F_RXCSUM_BIT);
+static netdev_features_t mtk_hw_features __ro_after_init;
+static netdev_features_t mtk_mt7628_hw_features __ro_after_init;
+static netdev_features_t mtk_empty_features __ro_after_init;
+
 void mtk_w32(struct mtk_eth *eth, u32 val, unsigned reg)
 {
 	__raw_writel(val, eth->base + reg);
@@ -3362,6 +3379,14 @@ static int mtk_hw_deinit(struct mtk_eth *eth)
 	return 0;
 }
 
+static void __init mtk_features_init(void)
+{
+	netdev_features_set_array(&mtk_hw_feature_set, &mtk_hw_features);
+	netdev_features_set_array(&mtk_mt7628_hw_feature_set,
+				  &mtk_mt7628_hw_features);
+	netdev_features_zero(&mtk_empty_features);
+}
+
 static int __init mtk_init(struct net_device *dev)
 {
 	struct mtk_mac *mac = netdev_priv(dev);
@@ -3376,6 +3401,8 @@ static int __init mtk_init(struct net_device *dev)
 			dev->dev_addr);
 	}
 
+	mtk_features_init();
+
 	return 0;
 }
 
@@ -3868,13 +3895,13 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)
 	eth->netdev[id]->netdev_ops = &mtk_netdev_ops;
 	eth->netdev[id]->base_addr = (unsigned long)eth->base;
 
-	eth->netdev[id]->hw_features = eth->soc->hw_features;
+	eth->netdev[id]->hw_features = *eth->soc->hw_features;
 	if (eth->hwlro)
 		eth->netdev[id]->hw_features |= NETIF_F_LRO;
 
-	eth->netdev[id]->vlan_features = eth->soc->hw_features &
+	eth->netdev[id]->vlan_features = *eth->soc->hw_features &
 		~(NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX);
-	eth->netdev[id]->features |= eth->soc->hw_features;
+	eth->netdev[id]->features |= *eth->soc->hw_features;
 	eth->netdev[id]->ethtool_ops = &mtk_ethtool_ops;
 
 	eth->netdev[id]->irq = eth->irq[0];
@@ -4170,7 +4197,7 @@ static int mtk_remove(struct platform_device *pdev)
 static const struct mtk_soc_data mt2701_data = {
 	.reg_map = &mtk_reg_map,
 	.caps = MT7623_CAPS | MTK_HWLRO,
-	.hw_features = MTK_HW_FEATURES,
+	.hw_features = &mtk_hw_features,
 	.required_clks = MT7623_CLKS_BITMAP,
 	.required_pctl = true,
 	.txrx = {
@@ -4186,7 +4213,7 @@ static const struct mtk_soc_data mt2701_data = {
 static const struct mtk_soc_data mt7621_data = {
 	.reg_map = &mtk_reg_map,
 	.caps = MT7621_CAPS,
-	.hw_features = MTK_HW_FEATURES,
+	.hw_features = &mtk_hw_features,
 	.required_clks = MT7621_CLKS_BITMAP,
 	.required_pctl = false,
 	.offload_version = 2,
@@ -4204,7 +4231,7 @@ static const struct mtk_soc_data mt7622_data = {
 	.reg_map = &mtk_reg_map,
 	.ana_rgc3 = 0x2028,
 	.caps = MT7622_CAPS | MTK_HWLRO,
-	.hw_features = MTK_HW_FEATURES,
+	.hw_features = &mtk_hw_features,
 	.required_clks = MT7622_CLKS_BITMAP,
 	.required_pctl = false,
 	.offload_version = 2,
@@ -4221,7 +4248,7 @@ static const struct mtk_soc_data mt7622_data = {
 static const struct mtk_soc_data mt7623_data = {
 	.reg_map = &mtk_reg_map,
 	.caps = MT7623_CAPS | MTK_HWLRO,
-	.hw_features = MTK_HW_FEATURES,
+	.hw_features = &mtk_hw_features,
 	.required_clks = MT7623_CLKS_BITMAP,
 	.required_pctl = true,
 	.offload_version = 2,
@@ -4239,7 +4266,7 @@ static const struct mtk_soc_data mt7629_data = {
 	.reg_map = &mtk_reg_map,
 	.ana_rgc3 = 0x128,
 	.caps = MT7629_CAPS | MTK_HWLRO,
-	.hw_features = MTK_HW_FEATURES,
+	.hw_features = &mtk_hw_features,
 	.required_clks = MT7629_CLKS_BITMAP,
 	.required_pctl = false,
 	.txrx = {
@@ -4256,6 +4283,7 @@ static const struct mtk_soc_data mt7986_data = {
 	.reg_map = &mt7986_reg_map,
 	.ana_rgc3 = 0x128,
 	.caps = MT7986_CAPS,
+	.hw_features = &mtk_empty_features,
 	.required_clks = MT7986_CLKS_BITMAP,
 	.required_pctl = false,
 	.txrx = {
@@ -4271,7 +4299,7 @@ static const struct mtk_soc_data mt7986_data = {
 static const struct mtk_soc_data rt5350_data = {
 	.reg_map = &mt7628_reg_map,
 	.caps = MT7628_CAPS,
-	.hw_features = MTK_HW_FEATURES_MT7628,
+	.hw_features = &mtk_mt7628_hw_features,
 	.required_clks = MT7628_CLKS_BITMAP,
 	.required_pctl = false,
 	.txrx = {
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
index 7405c97cda66..9620240885aa 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
@@ -11,6 +11,7 @@
 
 #include <linux/dma-mapping.h>
 #include <linux/netdevice.h>
+#include <linux/netdev_features_helper.h>
 #include <linux/of_net.h>
 #include <linux/u64_stats_sync.h>
 #include <linux/refcount.h>
@@ -40,15 +41,6 @@
 				 NETIF_MSG_IFUP | \
 				 NETIF_MSG_RX_ERR | \
 				 NETIF_MSG_TX_ERR)
-#define MTK_HW_FEATURES		(NETIF_F_IP_CSUM | \
-				 NETIF_F_RXCSUM | \
-				 NETIF_F_HW_VLAN_CTAG_TX | \
-				 NETIF_F_HW_VLAN_CTAG_RX | \
-				 NETIF_F_SG | NETIF_F_TSO | \
-				 NETIF_F_TSO6 | \
-				 NETIF_F_IPV6_CSUM |\
-				 NETIF_F_HW_TC)
-#define MTK_HW_FEATURES_MT7628	(NETIF_F_SG | NETIF_F_RXCSUM)
 #define NEXT_DESP_IDX(X, Y)	(((X) + 1) & ((Y) - 1))
 
 #define MTK_PP_HEADROOM		XDP_PACKET_HEADROOM
@@ -977,7 +969,7 @@ struct mtk_soc_data {
 	u32		required_clks;
 	bool		required_pctl;
 	u8		offload_version;
-	netdev_features_t hw_features;
+	const netdev_features_t *hw_features;
 	struct {
 		u32	txd_size;
 		u32	rxd_size;
