diff --git a/integration-cli/check_test.go b/integration-cli/check_test.go
index 6bab50f907..e98a5be4e0 100644
--- a/integration-cli/check_test.go
+++ b/integration-cli/check_test.go
@@ -13,7 +13,6 @@ import (
 	"testing"
 	"time"
 
-	"github.com/docker/docker/api/types/swarm"
 	"github.com/docker/docker/integration-cli/checker"
 	"github.com/docker/docker/integration-cli/cli"
 	"github.com/docker/docker/integration-cli/cli/build/fakestorage"
@@ -129,9 +128,7 @@ func (s *DockerRegistrySuite) SetUpTest(c *check.C) {
 	testRequires(c, DaemonIsLinux, RegistryHosting, SameHostDaemon)
 	s.reg = registry.NewV2(c)
 	s.reg.WaitReady(c)
-	s.d = daemon.New(c, dockerBinary, dockerdBinary, daemon.Config{
-		Experimental: testEnv.DaemonInfo.ExperimentalBuild,
-	})
+	s.d = daemon.New(c, dockerBinary, dockerdBinary, testdaemon.WithEnvironment(testEnv.Execution))
 }
 
 func (s *DockerRegistrySuite) TearDownTest(c *check.C) {
@@ -164,9 +161,7 @@ func (s *DockerSchema1RegistrySuite) SetUpTest(c *check.C) {
 	testRequires(c, DaemonIsLinux, RegistryHosting, NotArm64, SameHostDaemon)
 	s.reg = registry.NewV2(c, registry.Schema1)
 	s.reg.WaitReady(c)
-	s.d = daemon.New(c, dockerBinary, dockerdBinary, daemon.Config{
-		Experimental: testEnv.DaemonInfo.ExperimentalBuild,
-	})
+	s.d = daemon.New(c, dockerBinary, dockerdBinary, testdaemon.WithEnvironment(testEnv.Execution))
 }
 
 func (s *DockerSchema1RegistrySuite) TearDownTest(c *check.C) {
@@ -199,9 +194,7 @@ func (s *DockerRegistryAuthHtpasswdSuite) SetUpTest(c *check.C) {
 	testRequires(c, DaemonIsLinux, RegistryHosting, SameHostDaemon)
 	s.reg = registry.NewV2(c, registry.Htpasswd)
 	s.reg.WaitReady(c)
-	s.d = daemon.New(c, dockerBinary, dockerdBinary, daemon.Config{
-		Experimental: testEnv.DaemonInfo.ExperimentalBuild,
-	})
+	s.d = daemon.New(c, dockerBinary, dockerdBinary, testdaemon.WithEnvironment(testEnv.Execution))
 }
 
 func (s *DockerRegistryAuthHtpasswdSuite) TearDownTest(c *check.C) {
@@ -234,9 +227,7 @@ func (s *DockerRegistryAuthTokenSuite) OnTimeout(c *check.C) {
 
 func (s *DockerRegistryAuthTokenSuite) SetUpTest(c *check.C) {
 	testRequires(c, DaemonIsLinux, RegistryHosting, SameHostDaemon)
-	s.d = daemon.New(c, dockerBinary, dockerdBinary, daemon.Config{
-		Experimental: testEnv.DaemonInfo.ExperimentalBuild,
-	})
+	s.d = daemon.New(c, dockerBinary, dockerdBinary, testdaemon.WithEnvironment(testEnv.Execution))
 }
 
 func (s *DockerRegistryAuthTokenSuite) TearDownTest(c *check.C) {
@@ -276,9 +267,7 @@ func (s *DockerDaemonSuite) OnTimeout(c *check.C) {
 
 func (s *DockerDaemonSuite) SetUpTest(c *check.C) {
 	testRequires(c, DaemonIsLinux, SameHostDaemon)
-	s.d = daemon.New(c, dockerBinary, dockerdBinary, daemon.Config{
-		Experimental: testEnv.DaemonInfo.ExperimentalBuild,
-	})
+	s.d = daemon.New(c, dockerBinary, dockerdBinary, testdaemon.WithEnvironment(testEnv.Execution))
 }
 
 func (s *DockerDaemonSuite) TearDownTest(c *check.C) {
@@ -333,26 +322,18 @@ func (s *DockerSwarmSuite) SetUpTest(c *check.C) {
 }
 
 func (s *DockerSwarmSuite) AddDaemon(c *check.C, joinSwarm, manager bool) *daemon.Daemon {
-	d := daemon.New(c, dockerBinary, dockerdBinary, daemon.Config{
-		Experimental: testEnv.DaemonInfo.ExperimentalBuild,
-	}, testdaemon.WithSwarmPort(defaultSwarmPort+s.portIndex))
-	args := []string{"--iptables=false", "--swarm-default-advertise-addr=lo"} // avoid networking conflicts
-	d.StartWithBusybox(c, args...)
-
+	d := daemon.New(c, dockerBinary, dockerdBinary,
+		testdaemon.WithEnvironment(testEnv.Execution),
+		testdaemon.WithSwarmPort(defaultSwarmPort+s.portIndex),
+	)
 	if joinSwarm {
 		if len(s.daemons) > 0 {
-			tokens := s.daemons[0].JoinTokens(c)
-			token := tokens.Worker
-			if manager {
-				token = tokens.Manager
-			}
-			d.SwarmJoin(c, swarm.JoinRequest{
-				RemoteAddrs: []string{s.daemons[0].SwarmListenAddr()},
-				JoinToken:   token,
-			})
+			d.StartAndSwarmJoin(c, s.daemons[0].Daemon, manager)
 		} else {
-			d.SwarmInit(c, swarm.InitRequest{})
+			d.StartAndSwarmInit(c)
 		}
+	} else {
+		d.StartWithBusybox(c, "--iptables=false", "--swarm-default-advertise-addr=lo")
 	}
 
 	s.portIndex++
diff --git a/integration-cli/daemon/daemon.go b/integration-cli/daemon/daemon.go
index 0ec9e892b2..3087416ee0 100644
--- a/integration-cli/daemon/daemon.go
+++ b/integration-cli/daemon/daemon.go
@@ -30,21 +30,12 @@ type Daemon struct {
 	dockerBinary string
 }
 
-// Config holds docker daemon integration configuration
-type Config struct {
-	Experimental bool
-}
-
 // New returns a Daemon instance to be used for testing.
 // This will create a directory such as d123456789 in the folder specified by $DOCKER_INTEGRATION_DAEMON_DEST or $DEST.
 // The daemon will not automatically start.
-func New(t testingT, dockerBinary string, dockerdBinary string, config Config, ops ...func(*daemon.Daemon)) *Daemon {
+func New(t testingT, dockerBinary string, dockerdBinary string, ops ...func(*daemon.Daemon)) *Daemon {
 	ops = append(ops, daemon.WithDockerdBinary(dockerdBinary))
-	if config.Experimental {
-		ops = append(ops, daemon.WithExperimental)
-	}
 	d := daemon.New(t, ops...)
-
 	return &Daemon{
 		Daemon:       d,
 		dockerBinary: dockerBinary,
diff --git a/integration-cli/docker_cli_daemon_test.go b/integration-cli/docker_cli_daemon_test.go
index 2646de3fb7..975f06d2b4 100644
--- a/integration-cli/docker_cli_daemon_test.go
+++ b/integration-cli/docker_cli_daemon_test.go
@@ -32,6 +32,7 @@ import (
 	"github.com/docker/docker/integration-cli/checker"
 	"github.com/docker/docker/integration-cli/cli"
 	"github.com/docker/docker/integration-cli/daemon"
+	testdaemon "github.com/docker/docker/internal/test/daemon"
 	"github.com/docker/docker/opts"
 	"github.com/docker/docker/pkg/mount"
 	"github.com/docker/docker/pkg/stringid"
@@ -1432,9 +1433,7 @@ func (s *DockerDaemonSuite) TestDaemonRestartWithSocketAsVolume(c *check.C) {
 // os.Kill should kill daemon ungracefully, leaving behind container mounts.
 // A subsequent daemon restart should clean up said mounts.
 func (s *DockerDaemonSuite) TestCleanupMountsAfterDaemonAndContainerKill(c *check.C) {
-	d := daemon.New(c, dockerBinary, dockerdBinary, daemon.Config{
-		Experimental: testEnv.DaemonInfo.ExperimentalBuild,
-	})
+	d := daemon.New(c, dockerBinary, dockerdBinary, testdaemon.WithEnvironment(testEnv.Execution))
 	d.StartWithBusybox(c)
 
 	out, err := d.Cmd("run", "-d", "busybox", "top")
@@ -1472,9 +1471,7 @@ func (s *DockerDaemonSuite) TestCleanupMountsAfterDaemonAndContainerKill(c *chec
 
 // os.Interrupt should perform a graceful daemon shutdown and hence cleanup mounts.
 func (s *DockerDaemonSuite) TestCleanupMountsAfterGracefulShutdown(c *check.C) {
-	d := daemon.New(c, dockerBinary, dockerdBinary, daemon.Config{
-		Experimental: testEnv.DaemonInfo.ExperimentalBuild,
-	})
+	d := daemon.New(c, dockerBinary, dockerdBinary, testdaemon.WithEnvironment(testEnv.Execution))
 	d.StartWithBusybox(c)
 
 	out, err := d.Cmd("run", "-d", "busybox", "top")
@@ -1693,9 +1690,7 @@ func (s *DockerDaemonSuite) TestDaemonRestartLocalVolumes(c *check.C) {
 
 // FIXME(vdemeester) should be a unit test
 func (s *DockerDaemonSuite) TestDaemonCorruptedLogDriverAddress(c *check.C) {
-	d := daemon.New(c, dockerBinary, dockerdBinary, daemon.Config{
-		Experimental: testEnv.DaemonInfo.ExperimentalBuild,
-	})
+	d := daemon.New(c, dockerBinary, dockerdBinary, testdaemon.WithEnvironment(testEnv.Execution))
 	c.Assert(d.StartWithError("--log-driver=syslog", "--log-opt", "syslog-address=corrupted:42"), check.NotNil)
 	expected := "syslog-address should be in form proto://address"
 	icmd.RunCommand("grep", expected, d.LogFileName()).Assert(c, icmd.Success)
@@ -1703,9 +1698,7 @@ func (s *DockerDaemonSuite) TestDaemonCorruptedLogDriverAddress(c *check.C) {
 
 // FIXME(vdemeester) should be a unit test
 func (s *DockerDaemonSuite) TestDaemonCorruptedFluentdAddress(c *check.C) {
-	d := daemon.New(c, dockerBinary, dockerdBinary, daemon.Config{
-		Experimental: testEnv.DaemonInfo.ExperimentalBuild,
-	})
+	d := daemon.New(c, dockerBinary, dockerdBinary, testdaemon.WithEnvironment(testEnv.Execution))
 	c.Assert(d.StartWithError("--log-driver=fluentd", "--log-opt", "fluentd-address=corrupted:c"), check.NotNil)
 	expected := "invalid fluentd-address corrupted:c: "
 	icmd.RunCommand("grep", expected, d.LogFileName()).Assert(c, icmd.Success)
@@ -3080,9 +3073,7 @@ func (s *DockerDaemonSuite) TestDaemonIpcModeShareableFromConfig(c *check.C) {
 }
 
 func testDaemonStartIpcMode(c *check.C, from, mode string, valid bool) {
-	d := daemon.New(c, dockerBinary, dockerdBinary, daemon.Config{
-		Experimental: testEnv.DaemonInfo.ExperimentalBuild,
-	})
+	d := daemon.New(c, dockerBinary, dockerdBinary, testdaemon.WithEnvironment(testEnv.Execution))
 	c.Logf("Checking IpcMode %s set from %s\n", mode, from)
 	var serr error
 	switch from {
@@ -3183,7 +3174,7 @@ func (s *DockerDaemonSuite) TestDaemonRestartIpcMode(c *check.C) {
 // the daemon from starting
 func (s *DockerDaemonSuite) TestFailedPluginRemove(c *check.C) {
 	testRequires(c, DaemonIsLinux, IsAmd64, SameHostDaemon)
-	d := daemon.New(c, dockerBinary, dockerdBinary, daemon.Config{})
+	d := daemon.New(c, dockerBinary, dockerdBinary)
 	d.Start(c)
 	cli, err := client.NewClient(d.Sock(), api.DefaultVersion, nil, nil)
 	c.Assert(err, checker.IsNil)
diff --git a/integration-cli/docker_cli_external_graphdriver_unix_test.go b/integration-cli/docker_cli_external_graphdriver_unix_test.go
index e356154049..a52e58b2d2 100644
--- a/integration-cli/docker_cli_external_graphdriver_unix_test.go
+++ b/integration-cli/docker_cli_external_graphdriver_unix_test.go
@@ -15,6 +15,7 @@ import (
 	"github.com/docker/docker/daemon/graphdriver"
 	"github.com/docker/docker/daemon/graphdriver/vfs"
 	"github.com/docker/docker/integration-cli/daemon"
+	testdaemon "github.com/docker/docker/internal/test/daemon"
 	"github.com/docker/docker/pkg/archive"
 	"github.com/docker/docker/pkg/plugins"
 	"github.com/go-check/check"
@@ -52,9 +53,7 @@ type graphEventsCounter struct {
 }
 
 func (s *DockerExternalGraphdriverSuite) SetUpTest(c *check.C) {
-	s.d = daemon.New(c, dockerBinary, dockerdBinary, daemon.Config{
-		Experimental: testEnv.DaemonInfo.ExperimentalBuild,
-	})
+	s.d = daemon.New(c, dockerBinary, dockerdBinary, testdaemon.WithEnvironment(testEnv.Execution))
 }
 
 func (s *DockerExternalGraphdriverSuite) OnTimeout(c *check.C) {
diff --git a/integration-cli/docker_cli_external_volume_driver_unix_test.go b/integration-cli/docker_cli_external_volume_driver_unix_test.go
index ff3d50fb03..1553abda28 100644
--- a/integration-cli/docker_cli_external_volume_driver_unix_test.go
+++ b/integration-cli/docker_cli_external_volume_driver_unix_test.go
@@ -18,6 +18,7 @@ import (
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/integration-cli/checker"
 	"github.com/docker/docker/integration-cli/daemon"
+	testdaemon "github.com/docker/docker/internal/test/daemon"
 	"github.com/docker/docker/pkg/stringid"
 	"github.com/docker/docker/volume"
 	"github.com/go-check/check"
@@ -51,9 +52,7 @@ type DockerExternalVolumeSuite struct {
 
 func (s *DockerExternalVolumeSuite) SetUpTest(c *check.C) {
 	testRequires(c, SameHostDaemon)
-	s.d = daemon.New(c, dockerBinary, dockerdBinary, daemon.Config{
-		Experimental: testEnv.DaemonInfo.ExperimentalBuild,
-	})
+	s.d = daemon.New(c, dockerBinary, dockerdBinary, testdaemon.WithEnvironment(testEnv.Execution))
 	s.ec = &eventCounter{}
 }
 
diff --git a/integration-cli/docker_cli_info_test.go b/integration-cli/docker_cli_info_test.go
index 35a2532196..65091029ee 100644
--- a/integration-cli/docker_cli_info_test.go
+++ b/integration-cli/docker_cli_info_test.go
@@ -8,6 +8,7 @@ import (
 
 	"github.com/docker/docker/integration-cli/checker"
 	"github.com/docker/docker/integration-cli/daemon"
+	testdaemon "github.com/docker/docker/internal/test/daemon"
 	"github.com/go-check/check"
 )
 
@@ -71,9 +72,7 @@ func (s *DockerSuite) TestInfoFormat(c *check.C) {
 func (s *DockerSuite) TestInfoDiscoveryBackend(c *check.C) {
 	testRequires(c, SameHostDaemon, DaemonIsLinux)
 
-	d := daemon.New(c, dockerBinary, dockerdBinary, daemon.Config{
-		Experimental: testEnv.DaemonInfo.ExperimentalBuild,
-	})
+	d := daemon.New(c, dockerBinary, dockerdBinary, testdaemon.WithEnvironment(testEnv.Execution))
 	discoveryBackend := "consul://consuladdr:consulport/some/path"
 	discoveryAdvertise := "1.1.1.1:2375"
 	d.Start(c, fmt.Sprintf("--cluster-store=%s", discoveryBackend), fmt.Sprintf("--cluster-advertise=%s", discoveryAdvertise))
@@ -90,9 +89,7 @@ func (s *DockerSuite) TestInfoDiscoveryBackend(c *check.C) {
 func (s *DockerSuite) TestInfoDiscoveryInvalidAdvertise(c *check.C) {
 	testRequires(c, SameHostDaemon, DaemonIsLinux)
 
-	d := daemon.New(c, dockerBinary, dockerdBinary, daemon.Config{
-		Experimental: testEnv.DaemonInfo.ExperimentalBuild,
-	})
+	d := daemon.New(c, dockerBinary, dockerdBinary, testdaemon.WithEnvironment(testEnv.Execution))
 	discoveryBackend := "consul://consuladdr:consulport/some/path"
 
 	// --cluster-advertise with an invalid string is an error
@@ -109,9 +106,7 @@ func (s *DockerSuite) TestInfoDiscoveryInvalidAdvertise(c *check.C) {
 func (s *DockerSuite) TestInfoDiscoveryAdvertiseInterfaceName(c *check.C) {
 	testRequires(c, SameHostDaemon, Network, DaemonIsLinux)
 
-	d := daemon.New(c, dockerBinary, dockerdBinary, daemon.Config{
-		Experimental: testEnv.DaemonInfo.ExperimentalBuild,
-	})
+	d := daemon.New(c, dockerBinary, dockerdBinary, testdaemon.WithEnvironment(testEnv.Execution))
 	discoveryBackend := "consul://consuladdr:consulport/some/path"
 	discoveryAdvertise := "eth0"
 
@@ -182,9 +177,7 @@ func (s *DockerSuite) TestInfoDisplaysStoppedContainers(c *check.C) {
 func (s *DockerSuite) TestInfoDebug(c *check.C) {
 	testRequires(c, SameHostDaemon, DaemonIsLinux)
 
-	d := daemon.New(c, dockerBinary, dockerdBinary, daemon.Config{
-		Experimental: testEnv.DaemonInfo.ExperimentalBuild,
-	})
+	d := daemon.New(c, dockerBinary, dockerdBinary, testdaemon.WithEnvironment(testEnv.Execution))
 	d.Start(c, "--debug")
 	defer d.Stop(c)
 
@@ -205,9 +198,7 @@ func (s *DockerSuite) TestInsecureRegistries(c *check.C) {
 	registryCIDR := "192.168.1.0/24"
 	registryHost := "insecurehost.com:5000"
 
-	d := daemon.New(c, dockerBinary, dockerdBinary, daemon.Config{
-		Experimental: testEnv.DaemonInfo.ExperimentalBuild,
-	})
+	d := daemon.New(c, dockerBinary, dockerdBinary, testdaemon.WithEnvironment(testEnv.Execution))
 	d.Start(c, "--insecure-registry="+registryCIDR, "--insecure-registry="+registryHost)
 	defer d.Stop(c)
 
diff --git a/integration-cli/docker_cli_network_unix_test.go b/integration-cli/docker_cli_network_unix_test.go
index bd3cf54342..f3ecd62187 100644
--- a/integration-cli/docker_cli_network_unix_test.go
+++ b/integration-cli/docker_cli_network_unix_test.go
@@ -18,6 +18,7 @@ import (
 	"github.com/docker/docker/integration-cli/checker"
 	"github.com/docker/docker/integration-cli/cli"
 	"github.com/docker/docker/integration-cli/daemon"
+	testdaemon "github.com/docker/docker/internal/test/daemon"
 	"github.com/docker/docker/pkg/stringid"
 	"github.com/docker/docker/runconfig"
 	"github.com/docker/libnetwork/driverapi"
@@ -49,9 +50,7 @@ type DockerNetworkSuite struct {
 }
 
 func (s *DockerNetworkSuite) SetUpTest(c *check.C) {
-	s.d = daemon.New(c, dockerBinary, dockerdBinary, daemon.Config{
-		Experimental: testEnv.DaemonInfo.ExperimentalBuild,
-	})
+	s.d = daemon.New(c, dockerBinary, dockerdBinary, testdaemon.WithEnvironment(testEnv.Execution))
 }
 
 func (s *DockerNetworkSuite) TearDownTest(c *check.C) {
diff --git a/integration-cli/docker_cli_plugins_test.go b/integration-cli/docker_cli_plugins_test.go
index 8a936e3e44..c773fec5d5 100644
--- a/integration-cli/docker_cli_plugins_test.go
+++ b/integration-cli/docker_cli_plugins_test.go
@@ -473,7 +473,7 @@ func (s *DockerSuite) TestPluginUpgrade(c *check.C) {
 
 func (s *DockerSuite) TestPluginMetricsCollector(c *check.C) {
 	testRequires(c, DaemonIsLinux, Network, SameHostDaemon, IsAmd64)
-	d := daemon.New(c, dockerBinary, dockerdBinary, daemon.Config{})
+	d := daemon.New(c, dockerBinary, dockerdBinary)
 	d.Start(c)
 	defer d.Stop(c)
 
diff --git a/integration-cli/docker_hub_pull_suite_test.go b/integration-cli/docker_hub_pull_suite_test.go
index a8d6aedad3..125b8c10aa 100644
--- a/integration-cli/docker_hub_pull_suite_test.go
+++ b/integration-cli/docker_hub_pull_suite_test.go
@@ -7,6 +7,7 @@ import (
 
 	"github.com/docker/docker/integration-cli/checker"
 	"github.com/docker/docker/integration-cli/daemon"
+	testdaemon "github.com/docker/docker/internal/test/daemon"
 	"github.com/go-check/check"
 )
 
@@ -40,9 +41,7 @@ func newDockerHubPullSuite() *DockerHubPullSuite {
 // SetUpSuite starts the suite daemon.
 func (s *DockerHubPullSuite) SetUpSuite(c *check.C) {
 	testRequires(c, DaemonIsLinux, SameHostDaemon)
-	s.d = daemon.New(c, dockerBinary, dockerdBinary, daemon.Config{
-		Experimental: testEnv.DaemonInfo.ExperimentalBuild,
-	})
+	s.d = daemon.New(c, dockerBinary, dockerdBinary, testdaemon.WithEnvironment(testEnv.Execution))
 	s.d.Start(c)
 }
 
diff --git a/integration/build/build_session_test.go b/integration/build/build_session_test.go
index 1fde6a0f9a..af1a536769 100644
--- a/integration/build/build_session_test.go
+++ b/integration/build/build_session_test.go
@@ -9,8 +9,8 @@ import (
 
 	dclient "github.com/docker/docker/client"
 	"github.com/docker/docker/integration-cli/cli/build/fakecontext"
-	"github.com/docker/docker/integration-cli/daemon"
 	"github.com/docker/docker/integration-cli/request"
+	"github.com/docker/docker/internal/test/daemon"
 	"github.com/gotestyourself/gotestyourself/assert"
 	is "github.com/gotestyourself/gotestyourself/assert/cmp"
 	"github.com/moby/buildkit/session"
@@ -19,9 +19,7 @@ import (
 )
 
 func TestBuildWithSession(t *testing.T) {
-	d := daemon.New(t, "", "dockerd", daemon.Config{
-		Experimental: true,
-	})
+	d := daemon.New(t, daemon.WithExperimental)
 	d.StartWithBusybox(t)
 	defer d.Stop(t)
 
diff --git a/integration/build/build_squash_test.go b/integration/build/build_squash_test.go
index 7f264f1477..e8097fd811 100644
--- a/integration/build/build_squash_test.go
+++ b/integration/build/build_squash_test.go
@@ -10,17 +10,15 @@ import (
 
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/integration-cli/cli/build/fakecontext"
-	"github.com/docker/docker/integration-cli/daemon"
 	"github.com/docker/docker/integration/internal/container"
+	"github.com/docker/docker/internal/test/daemon"
 	"github.com/docker/docker/pkg/stdcopy"
 	"github.com/gotestyourself/gotestyourself/assert"
 	is "github.com/gotestyourself/gotestyourself/assert/cmp"
 )
 
 func TestBuildSquashParent(t *testing.T) {
-	d := daemon.New(t, "", "dockerd", daemon.Config{
-		Experimental: true,
-	})
+	d := daemon.New(t, daemon.WithExperimental)
 	d.StartWithBusybox(t)
 	defer d.Stop(t)
 
diff --git a/integration/config/config_test.go b/integration/config/config_test.go
index 6c72f2f8f9..26888b1784 100644
--- a/integration/config/config_test.go
+++ b/integration/config/config_test.go
@@ -26,8 +26,8 @@ func TestConfigList(t *testing.T) {
 	defer setupTest(t)()
 	d := swarm.NewSwarm(t, testEnv)
 	defer d.Stop(t)
-	client, err := client.NewClientWithOpts(client.WithHost((d.Sock())))
-	assert.NilError(t, err)
+	client := d.NewClientT(t)
+	defer client.Close()
 
 	ctx := context.Background()
 
@@ -117,8 +117,8 @@ func TestConfigsCreateAndDelete(t *testing.T) {
 	defer setupTest(t)()
 	d := swarm.NewSwarm(t, testEnv)
 	defer d.Stop(t)
-	client, err := client.NewClientWithOpts(client.WithHost((d.Sock())))
-	assert.NilError(t, err)
+	client := d.NewClientT(t)
+	defer client.Close()
 
 	ctx := context.Background()
 
@@ -145,8 +145,8 @@ func TestConfigsUpdate(t *testing.T) {
 	defer setupTest(t)()
 	d := swarm.NewSwarm(t, testEnv)
 	defer d.Stop(t)
-	client, err := client.NewClientWithOpts(client.WithHost((d.Sock())))
-	assert.NilError(t, err)
+	client := d.NewClientT(t)
+	defer client.Close()
 
 	ctx := context.Background()
 
@@ -196,9 +196,9 @@ func TestConfigsUpdate(t *testing.T) {
 func TestTemplatedConfig(t *testing.T) {
 	d := swarm.NewSwarm(t, testEnv)
 	defer d.Stop(t)
-
+	client := d.NewClientT(t)
+	defer client.Close()
 	ctx := context.Background()
-	client := swarm.GetClient(t, d)
 
 	referencedSecretName := "referencedsecret-" + t.Name()
 	referencedSecretSpec := swarmtypes.SecretSpec{
@@ -338,8 +338,8 @@ func TestConfigInspect(t *testing.T) {
 	defer setupTest(t)()
 	d := swarm.NewSwarm(t, testEnv)
 	defer d.Stop(t)
-	client, err := client.NewClientWithOpts(client.WithHost((d.Sock())))
-	assert.NilError(t, err)
+	client := d.NewClientT(t)
+	defer client.Close()
 
 	ctx := context.Background()
 
diff --git a/integration/internal/swarm/service.go b/integration/internal/swarm/service.go
index 031995f87a..3f5032976b 100644
--- a/integration/internal/swarm/service.go
+++ b/integration/internal/swarm/service.go
@@ -9,7 +9,6 @@ import (
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types/filters"
 	swarmtypes "github.com/docker/docker/api/types/swarm"
-	"github.com/docker/docker/client"
 	"github.com/docker/docker/internal/test/daemon"
 	"github.com/docker/docker/internal/test/environment"
 	"github.com/gotestyourself/gotestyourself/assert"
@@ -55,11 +54,7 @@ func NewSwarm(t *testing.T, testEnv *environment.Execution, ops ...func(*daemon.
 		ops = append(ops, daemon.WithExperimental)
 	}
 	d := daemon.New(t, ops...)
-	// avoid networking conflicts
-	args := []string{"--iptables=false", "--swarm-default-advertise-addr=lo"}
-	d.StartWithBusybox(t, args...)
-
-	d.SwarmInit(t, swarmtypes.InitRequest{})
+	d.StartAndSwarmInit(t)
 	return d
 }
 
@@ -73,7 +68,8 @@ func CreateService(t *testing.T, d *daemon.Daemon, opts ...ServiceSpecOpt) strin
 		o(&spec)
 	}
 
-	client := GetClient(t, d)
+	client := d.NewClientT(t)
+	defer client.Close()
 
 	resp, err := client.ServiceCreate(context.Background(), spec, types.ServiceCreateOptions{})
 	assert.NilError(t, err, "error creating service")
@@ -140,7 +136,8 @@ func ServiceWithName(name string) ServiceSpecOpt {
 
 // GetRunningTasks gets the list of running tasks for a service
 func GetRunningTasks(t *testing.T, d *daemon.Daemon, serviceID string) []swarmtypes.Task {
-	client := GetClient(t, d)
+	client := d.NewClientT(t)
+	defer client.Close()
 
 	filterArgs := filters.NewArgs()
 	filterArgs.Add("desired-state", "running")
@@ -156,7 +153,8 @@ func GetRunningTasks(t *testing.T, d *daemon.Daemon, serviceID string) []swarmty
 
 // ExecTask runs the passed in exec config on the given task
 func ExecTask(t *testing.T, d *daemon.Daemon, task swarmtypes.Task, config types.ExecConfig) types.HijackedResponse {
-	client := GetClient(t, d)
+	client := d.NewClientT(t)
+	defer client.Close()
 
 	ctx := context.Background()
 	resp, err := client.ContainerExecCreate(ctx, task.Status.ContainerStatus.ContainerID, config)
@@ -173,10 +171,3 @@ func ensureContainerSpec(spec *swarmtypes.ServiceSpec) {
 		spec.TaskTemplate.ContainerSpec = &swarmtypes.ContainerSpec{}
 	}
 }
-
-// GetClient creates a new client for the passed in swarm daemon.
-func GetClient(t *testing.T, d *daemon.Daemon) client.APIClient {
-	client, err := client.NewClientWithOpts(client.WithHost((d.Sock())))
-	assert.NilError(t, err)
-	return client
-}
diff --git a/integration/network/inspect_test.go b/integration/network/inspect_test.go
index 3f23c61ae2..8142ecdef2 100644
--- a/integration/network/inspect_test.go
+++ b/integration/network/inspect_test.go
@@ -20,8 +20,8 @@ func TestInspectNetwork(t *testing.T) {
 	defer setupTest(t)()
 	d := swarm.NewSwarm(t, testEnv)
 	defer d.Stop(t)
-	client, err := client.NewClientWithOpts(client.WithHost((d.Sock())))
-	assert.NilError(t, err)
+	client := d.NewClientT(t)
+	defer client.Close()
 
 	overlayName := "overlay1"
 	networkCreate := types.NetworkCreate{
diff --git a/integration/network/ipvlan/ipvlan_test.go b/integration/network/ipvlan/ipvlan_test.go
index 9de78f41bb..d42917db27 100644
--- a/integration/network/ipvlan/ipvlan_test.go
+++ b/integration/network/ipvlan/ipvlan_test.go
@@ -8,9 +8,9 @@ import (
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types/network"
 	dclient "github.com/docker/docker/client"
-	"github.com/docker/docker/integration-cli/daemon"
 	"github.com/docker/docker/integration/internal/container"
 	n "github.com/docker/docker/integration/network"
+	"github.com/docker/docker/internal/test/daemon"
 	"github.com/gotestyourself/gotestyourself/assert"
 	"github.com/gotestyourself/gotestyourself/skip"
 	"golang.org/x/net/context"
@@ -22,9 +22,7 @@ func TestDockerNetworkIpvlanPersistance(t *testing.T) {
 	skip.If(t, testEnv.IsRemoteDaemon())
 	skip.If(t, !ipvlanKernelSupport(), "Kernel doesn't support ipvlan")
 
-	d := daemon.New(t, "", "dockerd", daemon.Config{
-		Experimental: true,
-	})
+	d := daemon.New(t, daemon.WithExperimental)
 	d.StartWithBusybox(t)
 	defer d.Stop(t)
 
@@ -88,9 +86,7 @@ func TestDockerNetworkIpvlan(t *testing.T) {
 			test: testIpvlanAddressing,
 		},
 	} {
-		d := daemon.New(t, "", "dockerd", daemon.Config{
-			Experimental: true,
-		})
+		d := daemon.New(t, daemon.WithExperimental)
 		d.StartWithBusybox(t)
 
 		client, err := d.NewClient()
diff --git a/integration/network/service_test.go b/integration/network/service_test.go
index c619f54a2b..8efd7d1fac 100644
--- a/integration/network/service_test.go
+++ b/integration/network/service_test.go
@@ -17,8 +17,8 @@ func TestServiceWithPredefinedNetwork(t *testing.T) {
 	defer setupTest(t)()
 	d := swarm.NewSwarm(t, testEnv)
 	defer d.Stop(t)
-	client, err := client.NewClientWithOpts(client.WithHost((d.Sock())))
-	assert.NilError(t, err)
+	client := d.NewClientT(t)
+	defer client.Close()
 
 	hostName := "host"
 	var instances uint64 = 1
@@ -47,9 +47,8 @@ func TestServiceRemoveKeepsIngressNetwork(t *testing.T) {
 	defer setupTest(t)()
 	d := swarm.NewSwarm(t, testEnv)
 	defer d.Stop(t)
-
-	client, err := client.NewClientWithOpts(client.WithHost((d.Sock())))
-	assert.NilError(t, err)
+	client := d.NewClientT(t)
+	defer client.Close()
 
 	poll.WaitOn(t, swarmIngressReady(client), swarm.NetworkPoll)
 
diff --git a/integration/secret/secret_test.go b/integration/secret/secret_test.go
index 4a1e1b3dc7..5ad763a601 100644
--- a/integration/secret/secret_test.go
+++ b/integration/secret/secret_test.go
@@ -25,8 +25,8 @@ func TestSecretInspect(t *testing.T) {
 	defer setupTest(t)()
 	d := swarm.NewSwarm(t, testEnv)
 	defer d.Stop(t)
-	client, err := client.NewClientWithOpts(client.WithHost((d.Sock())))
-	assert.NilError(t, err)
+	client := d.NewClientT(t)
+	defer client.Close()
 
 	ctx := context.Background()
 
@@ -48,9 +48,8 @@ func TestSecretList(t *testing.T) {
 	defer setupTest(t)()
 	d := swarm.NewSwarm(t, testEnv)
 	defer d.Stop(t)
-	client, err := client.NewClientWithOpts(client.WithHost((d.Sock())))
-	assert.NilError(t, err)
-
+	client := d.NewClientT(t)
+	defer client.Close()
 	ctx := context.Background()
 
 	testName0 := "test0"
@@ -135,16 +134,15 @@ func TestSecretsCreateAndDelete(t *testing.T) {
 	defer setupTest(t)()
 	d := swarm.NewSwarm(t, testEnv)
 	defer d.Stop(t)
-	client, err := client.NewClientWithOpts(client.WithHost((d.Sock())))
-	assert.NilError(t, err)
-
+	client := d.NewClientT(t)
+	defer client.Close()
 	ctx := context.Background()
 
 	testName := "test_secret"
 	secretID := createSecret(ctx, t, client, testName, []byte("TESTINGDATA"), nil)
 
 	// create an already existin secret, daemon should return a status code of 409
-	_, err = client.SecretCreate(ctx, swarmtypes.SecretSpec{
+	_, err := client.SecretCreate(ctx, swarmtypes.SecretSpec{
 		Annotations: swarmtypes.Annotations{
 			Name: testName,
 		},
@@ -183,14 +181,12 @@ func TestSecretsUpdate(t *testing.T) {
 	defer setupTest(t)()
 	d := swarm.NewSwarm(t, testEnv)
 	defer d.Stop(t)
-	client, err := client.NewClientWithOpts(client.WithHost((d.Sock())))
-	assert.NilError(t, err)
-
+	client := d.NewClientT(t)
+	defer client.Close()
 	ctx := context.Background()
 
 	testName := "test_secret"
 	secretID := createSecret(ctx, t, client, testName, []byte("TESTINGDATA"), nil)
-	assert.NilError(t, err)
 
 	insp, _, err := client.SecretInspectWithRaw(ctx, secretID)
 	assert.NilError(t, err)
@@ -233,9 +229,9 @@ func TestSecretsUpdate(t *testing.T) {
 func TestTemplatedSecret(t *testing.T) {
 	d := swarm.NewSwarm(t, testEnv)
 	defer d.Stop(t)
-
+	client := d.NewClientT(t)
+	defer client.Close()
 	ctx := context.Background()
-	client := swarm.GetClient(t, d)
 
 	referencedSecretSpec := swarmtypes.SecretSpec{
 		Annotations: swarmtypes.Annotations{
diff --git a/integration/service/create_test.go b/integration/service/create_test.go
index 9522b059ef..767d78b368 100644
--- a/integration/service/create_test.go
+++ b/integration/service/create_test.go
@@ -20,8 +20,8 @@ func TestCreateServiceMultipleTimes(t *testing.T) {
 	defer setupTest(t)()
 	d := swarm.NewSwarm(t, testEnv)
 	defer d.Stop(t)
-	client, err := client.NewClientWithOpts(client.WithHost((d.Sock())))
-	assert.NilError(t, err)
+	client := d.NewClientT(t)
+	defer client.Close()
 
 	overlayName := "overlay1"
 	networkCreate := types.NetworkCreate{
@@ -78,8 +78,8 @@ func TestCreateWithDuplicateNetworkNames(t *testing.T) {
 	defer setupTest(t)()
 	d := swarm.NewSwarm(t, testEnv)
 	defer d.Stop(t)
-	client, err := client.NewClientWithOpts(client.WithHost((d.Sock())))
-	assert.NilError(t, err)
+	client := d.NewClientT(t)
+	defer client.Close()
 
 	name := "foo"
 	networkCreate := types.NetworkCreate{
@@ -140,8 +140,8 @@ func TestCreateServiceSecretFileMode(t *testing.T) {
 	defer setupTest(t)()
 	d := swarm.NewSwarm(t, testEnv)
 	defer d.Stop(t)
-	client, err := client.NewClientWithOpts(client.WithHost((d.Sock())))
-	assert.NilError(t, err)
+	client := d.NewClientT(t)
+	defer client.Close()
 
 	ctx := context.Background()
 	secretResp, err := client.SecretCreate(ctx, swarmtypes.SecretSpec{
@@ -221,8 +221,8 @@ func TestCreateServiceConfigFileMode(t *testing.T) {
 	defer setupTest(t)()
 	d := swarm.NewSwarm(t, testEnv)
 	defer d.Stop(t)
-	client, err := client.NewClientWithOpts(client.WithHost((d.Sock())))
-	assert.NilError(t, err)
+	client := d.NewClientT(t)
+	defer client.Close()
 
 	ctx := context.Background()
 	configResp, err := client.ConfigCreate(ctx, swarmtypes.ConfigSpec{
diff --git a/integration/service/inspect_test.go b/integration/service/inspect_test.go
index d4d342e643..e437f35888 100644
--- a/integration/service/inspect_test.go
+++ b/integration/service/inspect_test.go
@@ -23,8 +23,8 @@ func TestInspect(t *testing.T) {
 	defer setupTest(t)()
 	d := swarm.NewSwarm(t, testEnv)
 	defer d.Stop(t)
-	client, err := client.NewClientWithOpts(client.WithHost((d.Sock())))
-	assert.NilError(t, err)
+	client := d.NewClientT(t)
+	defer client.Close()
 
 	var now = time.Now()
 	var instances uint64 = 2
diff --git a/integration/service/network_test.go b/integration/service/network_test.go
index 6b8c891cd8..7db171a125 100644
--- a/integration/service/network_test.go
+++ b/integration/service/network_test.go
@@ -6,7 +6,6 @@ import (
 
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types/network"
-	"github.com/docker/docker/client"
 	"github.com/docker/docker/integration/internal/container"
 	"github.com/docker/docker/integration/internal/swarm"
 	"github.com/gotestyourself/gotestyourself/assert"
@@ -17,12 +16,12 @@ func TestDockerNetworkConnectAlias(t *testing.T) {
 	defer setupTest(t)()
 	d := swarm.NewSwarm(t, testEnv)
 	defer d.Stop(t)
-	client, err := client.NewClientWithOpts(client.WithHost((d.Sock())))
-	assert.NilError(t, err)
+	client := d.NewClientT(t)
+	defer client.Close()
 	ctx := context.Background()
 
 	name := "test-alias"
-	_, err = client.NetworkCreate(ctx, name, types.NetworkCreate{
+	_, err := client.NetworkCreate(ctx, name, types.NetworkCreate{
 		Driver:     "overlay",
 		Attachable: true,
 	})
diff --git a/internal/test/daemon/ops.go b/internal/test/daemon/ops.go
index 0176c19d93..288fe88070 100644
--- a/internal/test/daemon/ops.go
+++ b/internal/test/daemon/ops.go
@@ -1,5 +1,7 @@
 package daemon
 
+import "github.com/docker/docker/internal/test/environment"
+
 // WithExperimental sets the daemon in experimental mode
 func WithExperimental(d *Daemon) {
 	d.experimental = true
@@ -25,3 +27,12 @@ func WithSwarmListenAddr(listenAddr string) func(*Daemon) {
 		d.swarmListenAddr = listenAddr
 	}
 }
+
+// WithEnvironment sets options from internal/test/environment.Execution struct
+func WithEnvironment(e environment.Execution) func(*Daemon) {
+	return func(d *Daemon) {
+		if e.DaemonInfo.ExperimentalBuild {
+			d.experimental = true
+		}
+	}
+}
diff --git a/internal/test/daemon/service.go b/internal/test/daemon/service.go
index 26e6004ae1..a0541e9716 100644
--- a/internal/test/daemon/service.go
+++ b/internal/test/daemon/service.go
@@ -13,9 +13,7 @@ import (
 // ServiceConstructor defines a swarm service constructor function
 type ServiceConstructor func(*swarm.Service)
 
-// CreateServiceWithOptions creates a swarm service given the specified service constructors
-// and auth config
-func (d *Daemon) CreateServiceWithOptions(t assert.TestingT, opts types.ServiceCreateOptions, f ...ServiceConstructor) string {
+func (d *Daemon) createServiceWithOptions(t assert.TestingT, opts types.ServiceCreateOptions, f ...ServiceConstructor) string {
 	var service swarm.Service
 	for _, fn := range f {
 		fn(&service)
@@ -34,7 +32,7 @@ func (d *Daemon) CreateServiceWithOptions(t assert.TestingT, opts types.ServiceC
 
 // CreateService creates a swarm service given the specified service constructor
 func (d *Daemon) CreateService(t assert.TestingT, f ...ServiceConstructor) string {
-	return d.CreateServiceWithOptions(t, types.ServiceCreateOptions{}, f...)
+	return d.createServiceWithOptions(t, types.ServiceCreateOptions{}, f...)
 }
 
 // GetService returns the swarm service corresponding to the specified id
diff --git a/internal/test/daemon/swarm.go b/internal/test/daemon/swarm.go
index f0cf373468..f66c447ccb 100644
--- a/internal/test/daemon/swarm.go
+++ b/internal/test/daemon/swarm.go
@@ -14,6 +14,32 @@ const (
 	defaultSwarmListenAddr = "0.0.0.0"
 )
 
+// StartAndSwarmInit starts the daemon (with busybox) and init the swarm
+func (d *Daemon) StartAndSwarmInit(t testingT) {
+	// avoid networking conflicts
+	args := []string{"--iptables=false", "--swarm-default-advertise-addr=lo"}
+	d.StartWithBusybox(t, args...)
+
+	d.SwarmInit(t, swarm.InitRequest{})
+}
+
+// StartAndSwarmJoin starts the daemon (with busybox) and join the specified swarm as worker or manager
+func (d *Daemon) StartAndSwarmJoin(t testingT, leader *Daemon, manager bool) {
+	// avoid networking conflicts
+	args := []string{"--iptables=false", "--swarm-default-advertise-addr=lo"}
+	d.StartWithBusybox(t, args...)
+
+	tokens := leader.JoinTokens(t)
+	token := tokens.Worker
+	if manager {
+		token = tokens.Manager
+	}
+	d.SwarmJoin(t, swarm.JoinRequest{
+		RemoteAddrs: []string{leader.SwarmListenAddr()},
+		JoinToken:   token,
+	})
+}
+
 // SpecConstructor defines a swarm spec constructor
 type SpecConstructor func(*swarm.Spec)