diff --git a/NOTICE.txt b/NOTICE.txt
index cc9e26ed3c..1d687d16ec 100644
--- a/NOTICE.txt
+++ b/NOTICE.txt
@@ -534,7 +534,7 @@ Contents of "LICENSE":
 --------------------------------------------------------------------
 Dependency: github.com/elastic/beats/v7
 Version: v7.0.0
-Revision: 0dcb3dfebef7
+Revision: 1498938e22f3
 License type (autodetected): Apache-2.0
 
 --------------------------------------------------------------------
diff --git a/_meta/beat.yml b/_meta/beat.yml
index e6dfbef0a4..8e7ddde702 100644
--- a/_meta/beat.yml
+++ b/_meta/beat.yml
@@ -38,39 +38,6 @@ apm-server:
     # Url to expose expvar.
     #url: "/debug/vars"
 
-  # Instrumentation support for the server's HTTP endpoints and event publisher.
-  #instrumentation:
-    # Set to true to enable instrumentation of the APM Server itself.
-    #enabled: false
-
-    # Environment in which the APM Server is running on (eg: staging, production, etc.)
-    #environment: ""
-
-    # Remote hosts to report instrumentation results to.
-    #hosts:
-    #  - http://remote-apm-server:8200
-
-    # API Key for the remote APM Server(s).
-    # If api_key is set then secret_token will be ignored.
-    #api_key:
-
-    # Secret token for the remote APM Server(s).
-    #secret_token:
-
-    # Enable profiling of the server, recording profile samples as events.
-    #
-    # This feature is experimental.
-    #profiling:
-      #cpu:
-        # Set to true to enable CPU profiling.
-        #enabled: false
-        #interval: 60s
-        #duration: 10s
-      #heap:
-        # Set to true to enable heap profiling.
-        #enabled: false
-        #interval: 60s
-
   # A pipeline is a definition of processors applied to documents when ingesting them to Elasticsearch.
   # Using pipelines involves two steps:
   # (1) registering a pipeline
@@ -983,6 +950,43 @@ output.elasticsearch:
   # Kerberos realm.
   #kerberos.realm: ELASTIC
 
+#============================= Instrumentation =============================
+
+# Instrumentation support for the server's HTTP endpoints and event publisher.
+#instrumentation:
+
+  # Set to true to enable instrumentation of the APM Server itself.
+  #enabled: false
+
+  # Environment in which the APM Server is running on (eg: staging, production, etc.)
+  #environment: ""
+
+  # Hosts to report instrumentation results to.
+  # For reporting to itself, leave this field commented
+  #hosts:
+  #  - http://remote-apm-server:8200
+
+  # API Key for the remote APM Server(s).
+  # If api_key is set then secret_token will be ignored.
+  #api_key:
+
+  # Secret token for the remote APM Server(s).
+  #secret_token:
+
+  # Enable profiling of the server, recording profile samples as events.
+  #
+  # This feature is experimental.
+  #profiling:
+    #cpu:
+      # Set to true to enable CPU profiling.
+      #enabled: false
+      #interval: 60s
+      #duration: 10s
+  #heap:
+    # Set to true to enable heap profiling.
+    #enabled: false
+    #interval: 60s
+
 #================================= Paths ==================================
 
 # The home path for the apm-server installation. This is the default base path
diff --git a/apm-server.docker.yml b/apm-server.docker.yml
index 5397e160b3..8ec153c083 100644
--- a/apm-server.docker.yml
+++ b/apm-server.docker.yml
@@ -38,39 +38,6 @@ apm-server:
     # Url to expose expvar.
     #url: "/debug/vars"
 
-  # Instrumentation support for the server's HTTP endpoints and event publisher.
-  #instrumentation:
-    # Set to true to enable instrumentation of the APM Server itself.
-    #enabled: false
-
-    # Environment in which the APM Server is running on (eg: staging, production, etc.)
-    #environment: ""
-
-    # Remote hosts to report instrumentation results to.
-    #hosts:
-    #  - http://remote-apm-server:8200
-
-    # API Key for the remote APM Server(s).
-    # If api_key is set then secret_token will be ignored.
-    #api_key:
-
-    # Secret token for the remote APM Server(s).
-    #secret_token:
-
-    # Enable profiling of the server, recording profile samples as events.
-    #
-    # This feature is experimental.
-    #profiling:
-      #cpu:
-        # Set to true to enable CPU profiling.
-        #enabled: false
-        #interval: 60s
-        #duration: 10s
-      #heap:
-        # Set to true to enable heap profiling.
-        #enabled: false
-        #interval: 60s
-
   # A pipeline is a definition of processors applied to documents when ingesting them to Elasticsearch.
   # Using pipelines involves two steps:
   # (1) registering a pipeline
@@ -983,6 +950,43 @@ output.elasticsearch:
   # Kerberos realm.
   #kerberos.realm: ELASTIC
 
+#============================= Instrumentation =============================
+
+# Instrumentation support for the server's HTTP endpoints and event publisher.
+#instrumentation:
+
+  # Set to true to enable instrumentation of the APM Server itself.
+  #enabled: false
+
+  # Environment in which the APM Server is running on (eg: staging, production, etc.)
+  #environment: ""
+
+  # Hosts to report instrumentation results to.
+  # For reporting to itself, leave this field commented
+  #hosts:
+  #  - http://remote-apm-server:8200
+
+  # API Key for the remote APM Server(s).
+  # If api_key is set then secret_token will be ignored.
+  #api_key:
+
+  # Secret token for the remote APM Server(s).
+  #secret_token:
+
+  # Enable profiling of the server, recording profile samples as events.
+  #
+  # This feature is experimental.
+  #profiling:
+    #cpu:
+      # Set to true to enable CPU profiling.
+      #enabled: false
+      #interval: 60s
+      #duration: 10s
+  #heap:
+    # Set to true to enable heap profiling.
+    #enabled: false
+    #interval: 60s
+
 #================================= Paths ==================================
 
 # The home path for the apm-server installation. This is the default base path
diff --git a/apm-server.yml b/apm-server.yml
index 2759ed1683..527acd6038 100644
--- a/apm-server.yml
+++ b/apm-server.yml
@@ -38,39 +38,6 @@ apm-server:
     # Url to expose expvar.
     #url: "/debug/vars"
 
-  # Instrumentation support for the server's HTTP endpoints and event publisher.
-  #instrumentation:
-    # Set to true to enable instrumentation of the APM Server itself.
-    #enabled: false
-
-    # Environment in which the APM Server is running on (eg: staging, production, etc.)
-    #environment: ""
-
-    # Remote hosts to report instrumentation results to.
-    #hosts:
-    #  - http://remote-apm-server:8200
-
-    # API Key for the remote APM Server(s).
-    # If api_key is set then secret_token will be ignored.
-    #api_key:
-
-    # Secret token for the remote APM Server(s).
-    #secret_token:
-
-    # Enable profiling of the server, recording profile samples as events.
-    #
-    # This feature is experimental.
-    #profiling:
-      #cpu:
-        # Set to true to enable CPU profiling.
-        #enabled: false
-        #interval: 60s
-        #duration: 10s
-      #heap:
-        # Set to true to enable heap profiling.
-        #enabled: false
-        #interval: 60s
-
   # A pipeline is a definition of processors applied to documents when ingesting them to Elasticsearch.
   # Using pipelines involves two steps:
   # (1) registering a pipeline
@@ -983,6 +950,43 @@ output.elasticsearch:
   # Kerberos realm.
   #kerberos.realm: ELASTIC
 
+#============================= Instrumentation =============================
+
+# Instrumentation support for the server's HTTP endpoints and event publisher.
+#instrumentation:
+
+  # Set to true to enable instrumentation of the APM Server itself.
+  #enabled: false
+
+  # Environment in which the APM Server is running on (eg: staging, production, etc.)
+  #environment: ""
+
+  # Hosts to report instrumentation results to.
+  # For reporting to itself, leave this field commented
+  #hosts:
+  #  - http://remote-apm-server:8200
+
+  # API Key for the remote APM Server(s).
+  # If api_key is set then secret_token will be ignored.
+  #api_key:
+
+  # Secret token for the remote APM Server(s).
+  #secret_token:
+
+  # Enable profiling of the server, recording profile samples as events.
+  #
+  # This feature is experimental.
+  #profiling:
+    #cpu:
+      # Set to true to enable CPU profiling.
+      #enabled: false
+      #interval: 60s
+      #duration: 10s
+  #heap:
+    # Set to true to enable heap profiling.
+    #enabled: false
+    #interval: 60s
+
 #================================= Paths ==================================
 
 # The home path for the apm-server installation. This is the default base path
diff --git a/beater/beater.go b/beater/beater.go
index f4e363c2ee..6c03877d66 100644
--- a/beater/beater.go
+++ b/beater/beater.go
@@ -130,12 +130,14 @@ type beater struct {
 // Run runs the APM Server, blocking until the beater's Stop method is called,
 // or a fatal error occurs.
 func (bt *beater) Run(b *beat.Beat) error {
-	tracer, tracerServer, err := initTracer(b.Info, bt.config, bt.logger)
-	if err != nil {
-		return err
+
+	var tracerServer *tracerServer
+	var err error
+	if listener := b.Instrumentation.Listener(); listener != nil {
+		tracerServer = newTracerServer(bt.config, listener)
 	}
-	defer tracer.Close()
 
+	tracer := b.Instrumentation.Tracer()
 	runServer := runServer
 	if tracerServer != nil {
 		runServer = runServerWithTracerServer(runServer, tracerServer, tracer)
diff --git a/beater/server_test.go b/beater/server_test.go
index 2477f31885..aa3853c7bc 100644
--- a/beater/server_test.go
+++ b/beater/server_test.go
@@ -35,6 +35,7 @@ import (
 
 	"github.com/elastic/beats/v7/libbeat/beat"
 	"github.com/elastic/beats/v7/libbeat/common"
+	"github.com/elastic/beats/v7/libbeat/instrumentation"
 	"github.com/elastic/beats/v7/libbeat/logp"
 	"github.com/elastic/beats/v7/libbeat/outputs"
 	pubs "github.com/elastic/beats/v7/libbeat/publisher"
@@ -514,11 +515,15 @@ func setupServer(t *testing.T, cfg *common.Config, beatConfig *beat.BeatConfig,
 		pub = dummyPipeline(cfg, info)
 	}
 
+	instrumentation, err := instrumentation.New(baseConfig, info.Beat, info.Version)
+	require.NoError(t, err)
+
 	// create a beat
 	apmBeat := &beat.Beat{
-		Publisher: pub,
-		Info:      info,
-		Config:    beatConfig,
+		Publisher:       pub,
+		Info:            info,
+		Config:          beatConfig,
+		Instrumentation: instrumentation,
 	}
 	return setupBeater(t, apmBeat, baseConfig, beatConfig)
 }
diff --git a/beater/tracing.go b/beater/tracing.go
index 61c11e736a..3752d7d5c7 100644
--- a/beater/tracing.go
+++ b/beater/tracing.go
@@ -19,23 +19,16 @@ package beater
 
 import (
 	"context"
-	"fmt"
 	"net"
 	"net/http"
-	"net/url"
-	"os"
-	"time"
 
 	"go.elastic.co/apm"
-	"go.elastic.co/apm/transport"
 
-	"github.com/elastic/beats/v7/libbeat/beat"
 	"github.com/elastic/beats/v7/libbeat/logp"
 
 	"github.com/elastic/apm-server/beater/api"
 	"github.com/elastic/apm-server/beater/config"
 	logs "github.com/elastic/apm-server/log"
-	"github.com/elastic/apm-server/pipelistener"
 	"github.com/elastic/apm-server/publish"
 )
 
@@ -43,88 +36,14 @@ func init() {
 	apm.DefaultTracer.Close()
 }
 
-// initTracer configures and returns an apm.Tracer for tracing
-// the APM server's own execution. If the server is configured
-// to send tracing data to itself, it will return a tracerServer
-// that can be used for receiving trace data.
-func initTracer(info beat.Info, cfg *config.Config, logger *logp.Logger) (*apm.Tracer, *tracerServer, error) {
-	if !cfg.SelfInstrumentation.IsEnabled() {
-		os.Setenv("ELASTIC_APM_ACTIVE", "false")
-		logger.Infof("self instrumentation is disabled")
-	} else {
-		os.Setenv("ELASTIC_APM_ACTIVE", "true")
-		logger.Infof("self instrumentation is enabled")
-	}
-	if !cfg.SelfInstrumentation.IsEnabled() {
-		tracer, err := apm.NewTracer(info.Beat, info.Version)
-		return tracer, nil, err
-	}
-
-	if cfg.SelfInstrumentation.Profiling.CPU.IsEnabled() {
-		interval := cfg.SelfInstrumentation.Profiling.CPU.Interval
-		duration := cfg.SelfInstrumentation.Profiling.CPU.Duration
-		logger.Infof("CPU profiling: every %s for %s", interval, duration)
-		os.Setenv("ELASTIC_APM_CPU_PROFILE_INTERVAL", fmt.Sprintf("%dms", int(interval.Seconds()*1000)))
-		os.Setenv("ELASTIC_APM_CPU_PROFILE_DURATION", fmt.Sprintf("%dms", int(duration.Seconds()*1000)))
-	}
-	if cfg.SelfInstrumentation.Profiling.Heap.IsEnabled() {
-		interval := cfg.SelfInstrumentation.Profiling.Heap.Interval
-		logger.Infof("Heap profiling: every %s", interval)
-		os.Setenv("ELASTIC_APM_HEAP_PROFILE_INTERVAL", fmt.Sprintf("%dms", int(interval.Seconds()*1000)))
-	}
-
-	var tracerTransport transport.Transport
-	var tracerServer *tracerServer
-	if cfg.SelfInstrumentation.Hosts != nil {
-		// tracing destined for external host
-		t, err := transport.NewHTTPTransport()
-		if err != nil {
-			return nil, nil, err
-		}
-		t.SetServerURL(cfg.SelfInstrumentation.Hosts...)
-		if cfg.SelfInstrumentation.APIKey != "" {
-			t.SetAPIKey(cfg.SelfInstrumentation.APIKey)
-		} else {
-			t.SetSecretToken(cfg.SelfInstrumentation.SecretToken)
-		}
-		tracerTransport = t
-		logger.Infof("self instrumentation directed to %s", cfg.SelfInstrumentation.Hosts)
-	} else {
-		var err error
-		tracerServer, err = newTracerServer(cfg)
-		if err != nil {
-			return nil, nil, err
-		}
-		tracerTransport = tracerServer.transport
-	}
-
-	var environment string
-	if cfg.SelfInstrumentation.Environment != nil {
-		environment = *cfg.SelfInstrumentation.Environment
-	}
-	tracer, err := apm.NewTracerOptions(apm.TracerOptions{
-		ServiceName:        info.Beat,
-		ServiceVersion:     info.Version,
-		ServiceEnvironment: environment,
-		Transport:          tracerTransport,
-	})
-	if err != nil {
-		return nil, nil, err
-	}
-	tracer.SetLogger(logp.NewLogger(logs.Tracing))
-
-	return tracer, tracerServer, nil
-}
-
 type tracerServer struct {
-	cfg       *config.Config
-	logger    *logp.Logger
-	server    *http.Server
-	listener  net.Listener
-	transport transport.Transport
+	cfg      *config.Config
+	logger   *logp.Logger
+	server   *http.Server
+	listener net.Listener
 }
 
-func newTracerServer(cfg *config.Config) (*tracerServer, error) {
+func newTracerServer(cfg *config.Config, listener net.Listener) *tracerServer {
 	cfgCopy := *cfg // Copy cfg so we can disable auth
 	cfg = &cfgCopy
 	cfg.SecretToken = ""
@@ -137,30 +56,12 @@ func newTracerServer(cfg *config.Config) (*tracerServer, error) {
 		MaxHeaderBytes: cfg.MaxHeaderSize,
 	}
 
-	// Create an in-process net.Listener for the tracer. This enables us to:
-	// - avoid the network stack
-	// - avoid/ignore TLS for self-tracing
-	// - skip tracing when the requests come from the in-process transport
-	//   (i.e. to avoid recursive/repeated tracing.)
-	pipeListener := pipelistener.New()
-	pipeTransport, err := transport.NewHTTPTransport()
-	if err != nil {
-		return nil, err
-	}
-	pipeTransport.SetServerURL(&url.URL{Scheme: "http", Host: "localhost"})
-	pipeTransport.Client.Transport = &http.Transport{
-		DialContext:     pipeListener.DialContext,
-		MaxIdleConns:    100,
-		IdleConnTimeout: 90 * time.Second,
-	}
-
 	return &tracerServer{
-		cfg:       cfg,
-		logger:    logp.NewLogger(logs.Beater),
-		server:    server,
-		listener:  pipeListener,
-		transport: pipeTransport,
-	}, nil
+		cfg:      cfg,
+		logger:   logp.NewLogger(logs.Beater),
+		server:   server,
+		listener: listener,
+	}
 }
 
 func (s *tracerServer) serve(report publish.Reporter) error {
diff --git a/beater/tracing_test.go b/beater/tracing_test.go
index d4ca7aaec7..51b9e61338 100644
--- a/beater/tracing_test.go
+++ b/beater/tracing_test.go
@@ -18,8 +18,6 @@
 package beater
 
 import (
-	"net/http"
-	"net/http/httptest"
 	"os"
 	"testing"
 	"time"
@@ -79,68 +77,6 @@ func TestServerTracingEnabled(t *testing.T) {
 	}
 }
 
-func TestServerTracingExternal(t *testing.T) {
-	t.Run("no_auth", func(t *testing.T) {
-		testServerTracingExternal(t, "" /* Expecting no Authorization header */)
-	})
-	t.Run("secret_token_auth", func(t *testing.T) {
-		const secretToken = "s3cr3t"
-		testServerTracingExternal(t, "Bearer "+secretToken, m{"instrumentation": m{"secret_token": secretToken}})
-	})
-	t.Run("api_key_auth", func(t *testing.T) {
-		const apiKey = "bjB0czNjcjN0OnMzY3IzdA=="
-		testServerTracingExternal(t, "ApiKey "+apiKey, m{"instrumentation": m{"api_key": apiKey}})
-	})
-}
-
-func testServerTracingExternal(t *testing.T, expectedAuthorization string, extraConfigs ...map[string]interface{}) {
-	if testing.Short() {
-		t.Skip("skipping server test")
-	}
-
-	os.Setenv("ELASTIC_APM_API_REQUEST_TIME", "100ms")
-	defer os.Unsetenv("ELASTIC_APM_API_REQUEST_TIME")
-
-	// start up a fake remote apm-server
-	requests := make(chan *http.Request)
-	remote := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
-		w.WriteHeader(http.StatusAccepted)
-		requests <- r
-	}))
-	defer remote.Close()
-
-	// start a test apm-server
-	ucfg := common.MustNewConfigFrom(m{"instrumentation": m{
-		"enabled": true,
-		"hosts":   []string{"http://" + remote.Listener.Addr().String()},
-	}})
-	for _, extra := range extraConfigs {
-		err := ucfg.Merge(extra)
-		require.NoError(t, err)
-	}
-
-	apm, err := setupServer(t, ucfg, nil, nil)
-	require.NoError(t, err)
-	defer apm.Stop()
-
-	// make a transaction request
-	req := makeTransactionRequest(t, apm.baseURL)
-	req.Header.Add("Content-Type", "application/x-ndjson")
-	res, err := apm.client.Do(req)
-	assert.NoError(t, err)
-	assert.Equal(t, http.StatusAccepted, res.StatusCode, body(t, res))
-
-	// ensure the transaction is reported to the remote apm-server
-	select {
-	case r := <-requests:
-		assert.Equal(t, http.MethodPost, r.Method)
-		assert.Equal(t, api.IntakePath, r.RequestURI)
-		assert.Equal(t, expectedAuthorization, r.Header.Get("Authorization"))
-	case <-time.After(time.Second):
-		t.Fatal("timed out waiting for transaction to be received")
-	}
-}
-
 func TestServerTracingDisabled(t *testing.T) {
 	events, teardown := setupTestServerInstrumentation(t, false)
 	defer teardown()
diff --git a/changelogs/head.asciidoc b/changelogs/head.asciidoc
index cf3a225cae..b9f8b72995 100644
--- a/changelogs/head.asciidoc
+++ b/changelogs/head.asciidoc
@@ -23,3 +23,4 @@ https://github.com/elastic/apm-server/compare/7.8\...master[View commits]
 * Added user_agent.name to grouping key for page-load transaction metrics {pull}3886[3886]
 * Map the Jaeger attribute peer.service to span.destination.service.name {pull}3897[3897]
 * Add timeseries.instance to transaction.duration.histogram docs {pull}3904[3904]
+* Uses `instrumentation` config and APM tracer from libbeat, deprecating `apm-server.instrumentation` {pull}3836[3836]
diff --git a/cmd/root.go b/cmd/root.go
index 6dbe3edb39..2c4af01af9 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -39,34 +39,63 @@ const (
 	apmIndexPattern = "apm"
 )
 
-var libbeatConfigOverrides = common.MustNewConfigFrom(map[string]interface{}{
-	"logging": map[string]interface{}{
-		"metrics": map[string]interface{}{
-			"enabled": false,
-		},
-		"files": map[string]interface{}{
-			"rotateeverybytes": 10 * 1024 * 1024,
-		},
+var libbeatConfigOverrides = []cfgfile.ConditionalOverride{{
+	Check: func(_ *common.Config) bool {
+		return true
 	},
-	"setup": map[string]interface{}{
-		"template": map[string]interface{}{
-			"settings": map[string]interface{}{
-				"index": map[string]interface{}{
-					"codec": "best_compression",
-					"mapping": map[string]interface{}{
-						"total_fields": map[string]int{
-							"limit": 2000,
+	Config: common.MustNewConfigFrom(map[string]interface{}{
+		"logging": map[string]interface{}{
+			"metrics": map[string]interface{}{
+				"enabled": false,
+			},
+			"files": map[string]interface{}{
+				"rotateeverybytes": 10 * 1024 * 1024,
+			},
+		},
+		"setup": map[string]interface{}{
+			"template": map[string]interface{}{
+				"settings": map[string]interface{}{
+					"index": map[string]interface{}{
+						"codec": "best_compression",
+						"mapping": map[string]interface{}{
+							"total_fields": map[string]int{
+								"limit": 2000,
+							},
 						},
+						"number_of_shards": 1,
+					},
+					"_source": map[string]interface{}{
+						"enabled": true,
 					},
-					"number_of_shards": 1,
-				},
-				"_source": map[string]interface{}{
-					"enabled": true,
 				},
 			},
 		},
+	}),
+},
+	{
+		// TODO update libbeat to perform config mutations on a separate step
+		Check: func(cfg *common.Config) bool {
+			if !cfg.HasField("instrumentation") {
+				ok, err := cfg.Has("apm-server.instrumentation", -1)
+				if err != nil {
+					panic(err)
+				}
+				if ok {
+					child, err := cfg.Child("apm-server.instrumentation", -1)
+					if err != nil {
+						panic(err)
+					}
+					err = cfg.SetChild("instrumentation", -1, child)
+					if err != nil {
+						panic(err)
+					}
+				}
+			}
+			return true
+		},
+		Config: common.NewConfig(),
 	},
-})
+}
 
 // NewRootCommand returns the "apm-server" root command.
 func NewRootCommand(newBeat beat.Creator) *cmd.BeatsRootCmd {
@@ -81,12 +110,7 @@ func NewRootCommand(newBeat beat.Creator) *cmd.BeatsRootCmd {
 		},
 		IndexManagement: idxmgmt.MakeDefaultSupporter,
 		Processing:      processing.MakeDefaultObserverSupport(false),
-		ConfigOverrides: []cfgfile.ConditionalOverride{{
-			Check: func(_ *common.Config) bool {
-				return true
-			},
-			Config: libbeatConfigOverrides,
-		}},
+		ConfigOverrides: libbeatConfigOverrides,
 	}
 
 	rootCmd := cmd.GenRootCmdWithSettings(newBeat, settings)
diff --git a/cmd/root_test.go b/cmd/root_test.go
new file mode 100644
index 0000000000..0d51c5c254
--- /dev/null
+++ b/cmd/root_test.go
@@ -0,0 +1,47 @@
+// Licensed to Elasticsearch B.V. under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Elasticsearch B.V. licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package cmd
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+
+	"github.com/elastic/beats/v7/libbeat/cfgfile"
+)
+
+func TestOverrideLegacyInstrumentationConfig(t *testing.T) {
+	cfg, err := cfgfile.Load("testdata/legacy_instrumentation.yml", libbeatConfigOverrides)
+	require.NoError(t, err)
+	assert.True(t, cfg.HasField("instrumentation"))
+
+	child, err := cfg.Child("instrumentation", -1)
+	require.NoError(t, err)
+	assert.True(t, child.Enabled())
+}
+
+func TestConflictInstrumentationConfig(t *testing.T) {
+	cfg, err := cfgfile.Load("testdata/conflict_instrumentation.yml", libbeatConfigOverrides)
+	require.NoError(t, err)
+	assert.True(t, cfg.HasField("instrumentation"))
+
+	child, err := cfg.Child("instrumentation", -1)
+	require.NoError(t, err)
+	assert.False(t, child.Enabled())
+}
diff --git a/cmd/testdata/conflict_instrumentation.yml b/cmd/testdata/conflict_instrumentation.yml
new file mode 100644
index 0000000000..e005d64790
--- /dev/null
+++ b/cmd/testdata/conflict_instrumentation.yml
@@ -0,0 +1,6 @@
+apm-server:
+  instrumentation:
+    enabled: true
+
+instrumentation:
+  enabled: false
diff --git a/cmd/testdata/legacy_instrumentation.yml b/cmd/testdata/legacy_instrumentation.yml
new file mode 100644
index 0000000000..5e86e47539
--- /dev/null
+++ b/cmd/testdata/legacy_instrumentation.yml
@@ -0,0 +1,4 @@
+apm-server:
+  instrumentation:
+    enabled: true
+
diff --git a/go.mod b/go.mod
index d961396f85..196f963d5a 100644
--- a/go.mod
+++ b/go.mod
@@ -12,7 +12,7 @@ require (
 	github.com/dop251/goja v0.0.0-20200622111502-2faa37d3dedf // indirect
 	github.com/dop251/goja_nodejs v0.0.0-20200128125109-2d688c7e0ac4 // indirect
 	github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4
-	github.com/elastic/beats/v7 v7.0.0-alpha2.0.20200619162900-0dcb3dfebef7
+	github.com/elastic/beats/v7 v7.0.0-alpha2.0.20200624123740-1498938e22f3
 	github.com/elastic/go-elasticsearch/v7 v7.5.0
 	github.com/elastic/go-elasticsearch/v8 v8.0.0-20200210103600-aff00e5adfde
 	github.com/elastic/go-hdrhistogram v0.1.0
@@ -65,7 +65,7 @@ require (
 	golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4 // indirect
 	golang.org/x/text v0.3.3 // indirect
 	golang.org/x/time v0.0.0-20191024005414-555d28b269f0
-	golang.org/x/tools v0.0.0-20200622203043-20e05c1c8ffa // indirect
+	golang.org/x/tools v0.0.0-20200624060801-dcbf2a9ed15d // indirect
 	google.golang.org/grpc v1.29.1
 	gopkg.in/yaml.v2 v2.3.0
 	howett.net/plist v0.0.0-20200419221736-3b63eb3a43b5 // indirect
diff --git a/go.sum b/go.sum
index 02a619e220..e5d044152b 100644
--- a/go.sum
+++ b/go.sum
@@ -236,8 +236,8 @@ github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc=
 github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
 github.com/eclipse/paho.mqtt.golang v1.2.1-0.20200121105743-0d940dd29fd2/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts=
 github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
-github.com/elastic/beats/v7 v7.0.0-alpha2.0.20200619162900-0dcb3dfebef7 h1:eXc9GabMLjvAiearPJmK+Ls9TSh55JpqcETtI/W0bFI=
-github.com/elastic/beats/v7 v7.0.0-alpha2.0.20200619162900-0dcb3dfebef7/go.mod h1:IY6FXKy+I1TXsaKGC2nsHkHNgfWrCS9EECrdYdqxN7c=
+github.com/elastic/beats/v7 v7.0.0-alpha2.0.20200624123740-1498938e22f3 h1:5o2B+APePCFoXW9XDNJz83PBsIzInKJYT3MiFDYESwg=
+github.com/elastic/beats/v7 v7.0.0-alpha2.0.20200624123740-1498938e22f3/go.mod h1:IY6FXKy+I1TXsaKGC2nsHkHNgfWrCS9EECrdYdqxN7c=
 github.com/elastic/ecs v1.5.0 h1:/VEIBsRU4ecq2+U3RPfKNc6bFyomP6qnthYEcQZu8GU=
 github.com/elastic/ecs v1.5.0/go.mod h1:pgiLbQsijLOJvFR8OTILLu0Ni/R/foUNg0L+T6mU9b4=
 github.com/elastic/elastic-agent-client/v7 v7.0.0-20200601155656-d6a9eb4f6d07 h1:s/41t2QLLkaa83VlS5UuyKH0ctX3bG4RMnE3Eha+8fU=
@@ -1240,8 +1240,8 @@ golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapK
 golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
 golang.org/x/tools v0.0.0-20200216192241-b320d3a0f5a2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
 golang.org/x/tools v0.0.0-20200509030707-2212a7e161a5/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
-golang.org/x/tools v0.0.0-20200622203043-20e05c1c8ffa h1:mMXQKlWCw9mIWgVLLfiycDZjMHMMYqiuakI4E/l2xcA=
-golang.org/x/tools v0.0.0-20200622203043-20e05c1c8ffa/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200624060801-dcbf2a9ed15d h1:Y4+kqqCbf46GCNf04uMqIlDYf1FuyTqSLDGywuWdRUI=
+golang.org/x/tools v0.0.0-20200624060801-dcbf2a9ed15d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=