diff --git a/Documentation/howto/dpdk.rst b/Documentation/howto/dpdk.rst
index 04609b20bd21..02fc568770ee 100644
--- a/Documentation/howto/dpdk.rst
+++ b/Documentation/howto/dpdk.rst
@@ -401,10 +401,11 @@ Supported actions for hardware offload are:
 - Modification of IPv6 (set_field:<ADDR>->ipv6_src/ipv6_dst/mod_nw_ttl).
 - Clone/output (tnl_push and output) for encapsulating over a tunnel.
 - Tunnel pop, for packets received on physical ports.
+- Meter.
 
 .. note::
-  Tunnel offloads are experimental APIs in DPDK. In order to enable it,
-  compile with -DALLOW_EXPERIMENTAL_API.
+  Tunnel offloads and Meter offloads are experimental APIs in DPDK. To enable
+  these features, compile with -DALLOW_EXPERIMENTAL_API.
 
 Multiprocess
 ------------
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index 2c08a71c8db2..e3e0346c30dd 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -7277,6 +7277,11 @@ dpif_netdev_meter_set(struct dpif *dpif, ofproto_meter_id meter_id,
 
     ovs_mutex_unlock(&dp->meters_lock);
 
+    if (netdev_is_flow_api_enabled()) {
+        meter_offload_set(dpif_normalize_type(dpif_type(dpif)),
+                          meter_id, config);
+    }
+
     return 0;
 }
 
@@ -7287,7 +7292,7 @@ dpif_netdev_meter_get(const struct dpif *dpif,
 {
     struct dp_netdev *dp = get_dp_netdev(dpif);
     uint32_t meter_id = meter_id_.uint32;
-    const struct dp_meter *meter;
+    struct dp_meter *meter;
 
     if (meter_id >= MAX_METERS) {
         return EFBIG;
@@ -7313,8 +7318,21 @@ dpif_netdev_meter_get(const struct dpif *dpif,
 
         ovs_mutex_unlock(&meter->lock);
         stats->n_bands = i;
-    }
 
+        if (netdev_is_flow_api_enabled()) {
+            meter_offload_get(dpif_normalize_type(dpif_type(dpif)),
+                              meter_id_, stats);
+
+            meter->packet_count = stats->packet_in_count;
+            meter->byte_count = stats->byte_in_count;
+
+            /* nit: Meter offload currently only supports one band */
+            if (meter->n_bands) {
+                stats->bands[0].packet_count = stats->packet_in_count;
+                stats->bands[0].byte_count = stats->byte_in_count;
+            }
+        }
+    }
     return 0;
 }
 
@@ -7330,6 +7348,11 @@ dpif_netdev_meter_del(struct dpif *dpif,
     if (!error) {
         uint32_t meter_id = meter_id_.uint32;
 
+        if (netdev_is_flow_api_enabled()) {
+            meter_offload_del(dpif_normalize_type(dpif_type(dpif)),
+                              meter_id_, stats);
+        }
+
         ovs_mutex_lock(&dp->meters_lock);
         dp_meter_detach_free(&dp->meters, meter_id);
         ovs_mutex_unlock(&dp->meters_lock);
diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c
index 026b0daa8d83..c90b5c3fb776 100644
--- a/lib/dpif-netlink.c
+++ b/lib/dpif-netlink.c
@@ -4249,7 +4249,8 @@ dpif_netlink_meter_set(struct dpif *dpif_, ofproto_meter_id meter_id,
 
     err = dpif_netlink_meter_set__(dpif_, meter_id, config);
     if (!err && netdev_is_flow_api_enabled()) {
-        meter_offload_set(meter_id, config);
+        meter_offload_set(dpif_normalize_type(dpif_type(dpif_)),
+                          meter_id, config);
     }
 
     return err;
@@ -4348,7 +4349,8 @@ dpif_netlink_meter_get(const struct dpif *dpif, ofproto_meter_id meter_id,
     err = dpif_netlink_meter_get_stats(dpif, meter_id, stats, max_bands,
                                        OVS_METER_CMD_GET);
     if (!err && netdev_is_flow_api_enabled()) {
-        meter_offload_get(meter_id, stats);
+        meter_offload_get(dpif_normalize_type(dpif_type(dpif)),
+                          meter_id, stats);
     }
 
     return err;
@@ -4363,7 +4365,8 @@ dpif_netlink_meter_del(struct dpif *dpif, ofproto_meter_id meter_id,
     err  = dpif_netlink_meter_get_stats(dpif, meter_id, stats,
                                         max_bands, OVS_METER_CMD_DEL);
     if (!err && netdev_is_flow_api_enabled()) {
-        meter_offload_del(meter_id, stats);
+        meter_offload_del(dpif_normalize_type(dpif_type(dpif)),
+                          meter_id, stats);
     }
 
     return err;
diff --git a/lib/netdev-offload-provider.h b/lib/netdev-offload-provider.h
index 9108856d18d1..23d94b1b24ae 100644
--- a/lib/netdev-offload-provider.h
+++ b/lib/netdev-offload-provider.h
@@ -99,7 +99,8 @@ struct netdev_flow_api {
      * returned.
      *
      * The meter id specified through 'config->meter_id' is ignored. */
-    int (*meter_set)(ofproto_meter_id meter_id,
+    int (*meter_set)(const char *type,
+                     ofproto_meter_id meter_id,
                      struct ofputil_meter_config *config);
 
     /* Queries HW for meter stats with the given 'meter_id'. Store the stats
@@ -110,7 +111,8 @@ struct netdev_flow_api {
      * available statistics should be incremented, not replaced. Those fields
      * are packet_in_count, byte_in_count and band[]->byte_count and
      * band[]->packet_count. */
-    int (*meter_get)(ofproto_meter_id meter_id,
+    int (*meter_get)(const char *type,
+                     ofproto_meter_id meter_id,
                      struct ofputil_meter_stats *stats);
 
     /* Removes meter 'meter_id' from HW. Store the stats of dropped packets to
@@ -118,7 +120,8 @@ struct netdev_flow_api {
      *
      * 'stats' may be passed in as NULL if no stats are needed, See the above
      * function for additional details on the 'stats' usage. */
-    int (*meter_del)(ofproto_meter_id meter_id,
+    int (*meter_del)(const char *type,
+                     ofproto_meter_id meter_id,
                      struct ofputil_meter_stats *stats);
 
     /* Initializies the netdev flow api.
diff --git a/lib/netdev-offload-tc.c b/lib/netdev-offload-tc.c
index ce7f8ad97306..2e708df036d4 100644
--- a/lib/netdev-offload-tc.c
+++ b/lib/netdev-offload-tc.c
@@ -2892,7 +2892,8 @@ meter_free_police_index(uint32_t police_index)
 }
 
 static int
-meter_tc_set_policer(ofproto_meter_id meter_id,
+meter_tc_set_policer(const char *dpif_type,
+                     ofproto_meter_id meter_id,
                      struct ofputil_meter_config *config)
 {
     uint32_t police_index;
@@ -2900,6 +2901,11 @@ meter_tc_set_policer(ofproto_meter_id meter_id,
     bool add_policer;
     int err;
 
+    if (strcmp(dpif_type, "system")) {
+        VLOG_DBG("meter doesn't belongs to the system datapath. Skipping.");
+        return EOPNOTSUPP;
+    }
+
     if (!config->bands || config->n_bands < 1 ||
         config->bands[0].type != OFPMBT13_DROP) {
         return 0;
@@ -2946,12 +2952,18 @@ meter_tc_set_policer(ofproto_meter_id meter_id,
 }
 
 static int
-meter_tc_get_policer(ofproto_meter_id meter_id,
+meter_tc_get_policer(const char *dpif_type,
+                     ofproto_meter_id meter_id,
                      struct ofputil_meter_stats *stats)
 {
     uint32_t police_index;
     int err = ENOENT;
 
+    if (strcmp(dpif_type, "system")) {
+        VLOG_DBG("meter doesn't belongs to the system datapath. Skipping.");
+        return EOPNOTSUPP;
+    }
+
     if (!meter_id_lookup(meter_id.uint32, &police_index)) {
         err = tc_get_policer_action(police_index, stats);
         if (err) {
@@ -2965,12 +2977,18 @@ meter_tc_get_policer(ofproto_meter_id meter_id,
 }
 
 static int
-meter_tc_del_policer(ofproto_meter_id meter_id,
+meter_tc_del_policer(const char *dpif_type,
+                     ofproto_meter_id meter_id,
                      struct ofputil_meter_stats *stats)
 {
     uint32_t police_index;
     int err = ENOENT;
 
+    if (strcmp(dpif_type, "system")) {
+        VLOG_DBG("meter doesn't belongs to the system datapath. Skipping.");
+        return EOPNOTSUPP;
+    }
+
     if (!meter_id_lookup(meter_id.uint32, &police_index)) {
         err = tc_del_policer_action(police_index, stats);
         if (err && err != ENOENT) {
diff --git a/lib/netdev-offload.c b/lib/netdev-offload.c
index 4592262bd34e..52dc74c216a3 100644
--- a/lib/netdev-offload.c
+++ b/lib/netdev-offload.c
@@ -199,14 +199,15 @@ netdev_assign_flow_api(struct netdev *netdev)
 }
 
 void
-meter_offload_set(ofproto_meter_id meter_id,
+meter_offload_set(const char *dpif_type,
+                  ofproto_meter_id meter_id,
                   struct ofputil_meter_config *config)
 {
     struct netdev_registered_flow_api *rfa;
 
     CMAP_FOR_EACH (rfa, cmap_node, &netdev_flow_apis) {
         if (rfa->flow_api->meter_set) {
-            int ret = rfa->flow_api->meter_set(meter_id, config);
+            int ret = rfa->flow_api->meter_set(dpif_type, meter_id, config);
             if (ret) {
                 VLOG_DBG_RL(&rl, "Failed setting meter %u for flow api %s, "
                             "error %d", meter_id.uint32, rfa->flow_api->type,
@@ -219,13 +220,15 @@ meter_offload_set(ofproto_meter_id meter_id,
 }
 
 int
-meter_offload_get(ofproto_meter_id meter_id, struct ofputil_meter_stats *stats)
+meter_offload_get(const char *dpif_type,
+                  ofproto_meter_id meter_id,
+                  struct ofputil_meter_stats *stats)
 {
     struct netdev_registered_flow_api *rfa;
 
     CMAP_FOR_EACH (rfa, cmap_node, &netdev_flow_apis) {
         if (rfa->flow_api->meter_get) {
-            int ret = rfa->flow_api->meter_get(meter_id, stats);
+            int ret = rfa->flow_api->meter_get(dpif_type, meter_id, stats);
             if (ret) {
                 VLOG_DBG_RL(&rl, "Failed getting meter %u for flow api %s, "
                             "error %d", meter_id.uint32, rfa->flow_api->type,
@@ -238,13 +241,15 @@ meter_offload_get(ofproto_meter_id meter_id, struct ofputil_meter_stats *stats)
 }
 
 int
-meter_offload_del(ofproto_meter_id meter_id, struct ofputil_meter_stats *stats)
+meter_offload_del(const char *dpif_type,
+                  ofproto_meter_id meter_id,
+                  struct ofputil_meter_stats *stats)
 {
     struct netdev_registered_flow_api *rfa;
 
     CMAP_FOR_EACH (rfa, cmap_node, &netdev_flow_apis) {
         if (rfa->flow_api->meter_del) {
-            int ret = rfa->flow_api->meter_del(meter_id, stats);
+            int ret = rfa->flow_api->meter_del(dpif_type, meter_id, stats);
             if (ret) {
                 VLOG_DBG_RL(&rl, "Failed deleting meter %u for flow api %s, "
                             "error %d", meter_id.uint32, rfa->flow_api->type,
diff --git a/lib/netdev-offload.h b/lib/netdev-offload.h
index edc843cd99a3..b52d642bf8ab 100644
--- a/lib/netdev-offload.h
+++ b/lib/netdev-offload.h
@@ -158,9 +158,12 @@ int netdev_ports_flow_get(const char *dpif_type, struct match *match,
 int netdev_ports_get_n_flows(const char *dpif_type,
                              odp_port_t port_no, uint64_t *n_flows);
 
-void meter_offload_set(ofproto_meter_id, struct ofputil_meter_config *);
-int meter_offload_get(ofproto_meter_id, struct ofputil_meter_stats *);
-int meter_offload_del(ofproto_meter_id, struct ofputil_meter_stats *);
+void meter_offload_set(const char *dpif_type, ofproto_meter_id,
+                       struct ofputil_meter_config *);
+int meter_offload_get(const char *dpif_type, ofproto_meter_id,
+                      struct ofputil_meter_stats *);
+int meter_offload_del(const char *dpif_type, ofproto_meter_id,
+                      struct ofputil_meter_stats *);
 
 #ifdef  __cplusplus
 }
