Yes, this is the expected behavior. I'm not sure if there's a document that explicitly, because Profile doesn't seem to explain it very well, and that I would assume is the most authoritative document on the matter, but it is indeed the way it works.
Whenever you include Profile in a Metadata API retrieve request (and, for consistency, this is how Change Sets also work), you always get all of the basic profile permissions, including Custom Permissions, Login Hour Restrictions, Login IP Restrictions, and all User Permissions (like API Enabled, Modify All Data, Customize Application, etc).
Whenever you deploy profiles, all of these settings are also deployed. The only permissions that are not retrieved or deployed by default are those that are related to customizable objects that you can deploy. This includes pages, classes, fields, objects, and record types. To explicitly retrieve those settings, you have to also include the related metadata items, such as adding the class, page, field, or object to the change set or package.xml file.
If you don't want to copy the standard permissions, you have to explicitly strip them out of the related XML files. There's no way to do this with a change set, because salesforce.com implicitly builds a package.xml for you in the background when you upload your change set. However, when you're using the Metadata API, you can always retrieve profiles, strip out the permissions you're not interested in modifying, and then deploying the XML file.
Permissions that are not explicitly listed in the ProfileName.profile file will not be modified, with two exceptions. Stripping out the Login IP Ranges has the effect of deleting all existing Login IP Ranges for the profile, and stripping out the Login Hours has the effect of deleting all Login Hours for the profile.