diff --git a/cli/command/service/update_test.go b/cli/command/service/update_test.go
index 08fe248769..3a112f2aff 100644
--- a/cli/command/service/update_test.go
+++ b/cli/command/service/update_test.go
@@ -1,11 +1,13 @@
 package service
 
 import (
+	"context"
 	"reflect"
 	"sort"
 	"testing"
 	"time"
 
+	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types/container"
 	mounttypes "github.com/docker/docker/api/types/mount"
 	"github.com/docker/docker/api/types/swarm"
@@ -382,3 +384,61 @@ func TestValidatePort(t *testing.T) {
 		assert.Error(t, err, e)
 	}
 }
+
+type secretAPIClientMock struct {
+	listResult []swarm.Secret
+}
+
+func (s secretAPIClientMock) SecretList(ctx context.Context, options types.SecretListOptions) ([]swarm.Secret, error) {
+	return s.listResult, nil
+}
+func (s secretAPIClientMock) SecretCreate(ctx context.Context, secret swarm.SecretSpec) (types.SecretCreateResponse, error) {
+	return types.SecretCreateResponse{}, nil
+}
+func (s secretAPIClientMock) SecretRemove(ctx context.Context, id string) error {
+	return nil
+}
+func (s secretAPIClientMock) SecretInspectWithRaw(ctx context.Context, name string) (swarm.Secret, []byte, error) {
+	return swarm.Secret{}, []byte{}, nil
+}
+func (s secretAPIClientMock) SecretUpdate(ctx context.Context, id string, version swarm.Version, secret swarm.SecretSpec) error {
+	return nil
+}
+
+// TestUpdateSecretUpdateInPlace tests the ability to update the "target" of an secret with "docker service update"
+// by combining "--secret-rm" and "--secret-add" for the same secret.
+func TestUpdateSecretUpdateInPlace(t *testing.T) {
+	apiClient := secretAPIClientMock{
+		listResult: []swarm.Secret{
+			{
+				ID:   "tn9qiblgnuuut11eufquw5dev",
+				Spec: swarm.SecretSpec{Annotations: swarm.Annotations{Name: "foo"}},
+			},
+		},
+	}
+
+	flags := newUpdateCommand(nil).Flags()
+	flags.Set("secret-add", "source=foo,target=foo2")
+	flags.Set("secret-rm", "foo")
+
+	secrets := []*swarm.SecretReference{
+		{
+			File: &swarm.SecretReferenceFileTarget{
+				Name: "foo",
+				UID:  "0",
+				GID:  "0",
+				Mode: 292,
+			},
+			SecretID:   "tn9qiblgnuuut11eufquw5dev",
+			SecretName: "foo",
+		},
+	}
+
+	updatedSecrets, err := getUpdatedSecrets(apiClient, flags, secrets)
+
+	assert.Equal(t, err, nil)
+	assert.Equal(t, len(updatedSecrets), 1)
+	assert.Equal(t, updatedSecrets[0].SecretID, "tn9qiblgnuuut11eufquw5dev")
+	assert.Equal(t, updatedSecrets[0].SecretName, "foo")
+	assert.Equal(t, updatedSecrets[0].File.Name, "foo2")
+}
diff --git a/client/interface.go b/client/interface.go
index 00b9adea32..924b22bc04 100644
--- a/client/interface.go
+++ b/client/interface.go
@@ -166,4 +166,5 @@ type SecretAPIClient interface {
 	SecretCreate(ctx context.Context, secret swarm.SecretSpec) (types.SecretCreateResponse, error)
 	SecretRemove(ctx context.Context, id string) error
 	SecretInspectWithRaw(ctx context.Context, name string) (swarm.Secret, []byte, error)
+	SecretUpdate(ctx context.Context, id string, version swarm.Version, secret swarm.SecretSpec) error
 }
diff --git a/client/secret_update.go b/client/secret_update.go
new file mode 100644
index 0000000000..b94e24aab0
--- /dev/null
+++ b/client/secret_update.go
@@ -0,0 +1,19 @@
+package client
+
+import (
+	"net/url"
+	"strconv"
+
+	"github.com/docker/docker/api/types/swarm"
+	"golang.org/x/net/context"
+)
+
+// SecretUpdate updates a Secret. Currently, the only part of a secret spec
+// which can be updated is Labels.
+func (cli *Client) SecretUpdate(ctx context.Context, id string, version swarm.Version, secret swarm.SecretSpec) error {
+	query := url.Values{}
+	query.Set("version", strconv.FormatUint(version.Index, 10))
+	resp, err := cli.post(ctx, "/secrets/"+id+"/update", query, secret, nil)
+	ensureReaderClosed(resp)
+	return err
+}
diff --git a/client/secret_update_test.go b/client/secret_update_test.go
new file mode 100644
index 0000000000..c620985bd5
--- /dev/null
+++ b/client/secret_update_test.go
@@ -0,0 +1,49 @@
+package client
+
+import (
+	"bytes"
+	"fmt"
+	"io/ioutil"
+	"net/http"
+	"strings"
+	"testing"
+
+	"golang.org/x/net/context"
+
+	"github.com/docker/docker/api/types/swarm"
+)
+
+func TestSecretUpdateError(t *testing.T) {
+	client := &Client{
+		client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")),
+	}
+
+	err := client.SecretUpdate(context.Background(), "secret_id", swarm.Version{}, swarm.SecretSpec{})
+	if err == nil || err.Error() != "Error response from daemon: Server error" {
+		t.Fatalf("expected a Server Error, got %v", err)
+	}
+}
+
+func TestSecretUpdate(t *testing.T) {
+	expectedURL := "/secrets/secret_id/update"
+
+	client := &Client{
+		client: newMockClient(func(req *http.Request) (*http.Response, error) {
+			if !strings.HasPrefix(req.URL.Path, expectedURL) {
+				return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL)
+			}
+			if req.Method != "POST" {
+				return nil, fmt.Errorf("expected POST method, got %s", req.Method)
+			}
+			return &http.Response{
+				StatusCode: http.StatusOK,
+				Body:       ioutil.NopCloser(bytes.NewReader([]byte("body"))),
+			}, nil
+		}),
+	}
+
+	err := client.SecretUpdate(context.Background(), "secret_id", swarm.Version{}, swarm.SecretSpec{})
+	if err != nil {
+		t.Fatal(err)
+	}
+}